BZOJ 4453 cys就是要拿英魂!

2022-03-18 04:19:52 字數 1667 閱讀 4553

題鏈:

題解:

字尾陣列,離線詢問,棧

看了一堆題解才看懂,太弱啦 ~

如果對於乙個區間[l,r]有兩個字尾i,j,(令 irank[j],那麼i肯定比j優。

2).如果rank[i]=r?j+1,那麼i比j更優。

所以,從後向前遍歷一遍字串,每次把遍歷到的當前位置固定為上述區間的左端點l,

那麼後面的區間就會被分為若干塊,每一塊裡面的位置作為右端點的答案相同。也就是說答案是呈區間分部的。

所以對於每次遍歷到的左端點 i,首先求出它所影響的區間範圍[i,r']

然後在把左端點為 i的詢問回答了。

但是怎樣做到上述的兩個操作呢:求出影響範圍,回答詢問

學習了各大博主的解法:

維護乙個棧,裡面按順序儲存著乙個個的區間(之前不是說答案連呈區間分部分,維護的就是這些區間,儲存當前區間的左右端點和答案)

然後就可以在棧裡面搞事情了。

1).求出影響範圍:

判斷棧頂區間是否可以被當前的 i點的影響範圍覆蓋:

可以全部覆蓋的話就移除棧頂,然後繼續判斷。

無法覆蓋的話就把答案為 i 的那個區間放在棧頂。

部分覆蓋的話就在棧頂區間裡二分出準確位置,然後把棧頂區間的縮小,並把答案為 i 的那個區間放在棧頂。

2).回答詢問:

直接二分出詢問的右端點在棧裡面的哪個答案區間就好了。

建議直接看看**的實現。

**:

#include#include#include#include#define	maxn 105000

#define filein(x) freopen(#x".in","r",stdin);

#define fileout(x) freopen(#x".out","w",stdout);

using namespace std;

struct stackstk[maxn];

struct query

}q[maxn];

char s[maxn];

int sa[maxn],rak[maxn],hei[maxn];

int ans[maxn],stm[maxn][20],log2[maxn];

void build(int n,int m)

for(int i=0;ir) swap(l,r); l++;

k=log2[r-l+1];

return min(stm[l+(1lcp=lcp(i,j);

return lcp>=r-j+1;

}void solve(int n,int m);

for(;q[j].l==n-1&&j<=m;j++)ans[q[j].id]=stk[top].p+1;

for(int i=n-2;fg=0,i>=0&&j<=m;i--)

if(fg)

stk[top].l=pos+1;

} else pos=stk[top].l-1;

stk[++top].r=pos;

stk[top].l=stk[top].p=i;

for(;q[j].l==i&&j<=m;j++)

BZOJ4453 cys就是要拿英魂!

description 第一行是乙個字串s,表示pps放的技能 第二行乙個正整數q,表示詢問個數 接下來q行,每行兩個正整數 l,r 表示詢問區間 l,r 中的字典序最大的子串。output q行,每行乙個正整數,表示該區間內字典序最大的子串的起始位置。sample input lets go mo...

BZOJ2844 albus就是要第乙個出場

傳送門 給定乙個含 n 個自然數的集合s,將 2s中所有集合的所有元素的異或和從小到大排列 下標從 1 開始 求ta r在其中第一次出現的下標 保證給出的數出現過 對 10086 取模.1 n 105 ai 109.首先tar 0的情況最好先特判掉.然後我們要求的是從 s 中取若干元素 可以不取 異...

bzoj 2844 albus就是要第乙個出場

首先就是乙個線性基。然後不能放進去的相當於0,然後列舉前多少位和m相同,那麼後一位比m小的方案累加入答案即可。ac 如下 include define mod 10086 using namespace std int n,m,cnt,bin 35 bs 35 s 35 bool ins int x...