首先把所有串拼起來,後插入的串在前面,得到乙個大串。
那麼任意時刻,每個串是由這個大串的若干個不相交的子串從左到右拼接而成。
用線段樹維護每個串,每個節點維護乙個標記,表示區間內的串要加上什麼字首。
用可持久化線段樹維護這些串和標記,那麼合併就是線段樹的合併,因為取值區間互不相交,所以每次合併的複雜度為$o(\log l)$。
這樣就可以在$o(m\log n\log l)$的時間內支援區間加操作。
然後考慮如何計算區間lcp,設$height_i=lcp(s_i,s_)$,那麼詢問$[l,r]$就是詢問$\min(height_l,height_,...,height_)$。
用線段樹維護$height$,每當區間加的時候,對$height$的修改就是區間加上乙個定值,然後兩端點暴力重新計算lcp。
計算兩個串的lcp可以考慮維護hash值,然後二分答案,單次查詢的複雜度為$o(\log^2l)$。
時間複雜度$o(m(\log n+\log l)\log l)$。
#include#include#includeusing namespace std;
typedef unsigned int u;
const int n=50010,m=600010,maxn=131100;
int n,m,i,j,x,len,cur,st[n],en[n],q[n][3],stq[n],enq[n];u po[m];
char op[9],s[m],pool[m],str[m];
int pre[maxn],t[n],h[maxn],tag[maxn];
namespace ds
int build(int a,int b,int c,int d)
int mid=(a+b)>>1;
if(c<=mid)l[x]=build(a,mid,c,d);
if(d>mid)r[x]=build(mid+1,b,c,d);
return up(x),x;
}int merge(int x,int y,int a,int b)
inline u hash(int x,int k)
return h*po[v[x]]+f[x];}}
inline void ins(int x,int p)
inline void down(int x)
void push(int x,int a,int b,int c,int d,int p)
down(x);
int mid=(a+b)>>1;
if(c<=mid)push(x<<1,a,mid,c,d,p);
if(d>mid)push(x<<1|1,mid+1,b,c,d,p);
}void root(int x,int a,int b,int c)
down(x);
int mid=(a+b)>>1;
if(c<=mid)root(x<<1,a,mid,c);else root(x<<1|1,mid+1,b,c);
}inline int lcp(int x,int y)
return t;
}inline void tag1(int x,int p)
inline void pb(int x)
inline void up(int x)
void build(int x,int a,int b)
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b);
up(x);
}void cal(int x,int a,int b,int c)
pb(x);
int mid=(a+b)>>1;
if(c<=mid)cal(x<<1,a,mid,c);else cal(x<<1|1,mid+1,b,c);
up(x);
}void change(int x,int a,int b,int c,int d,int p)
pb(x);
int mid=(a+b)>>1;
if(c<=mid)change(x<<1,a,mid,c,d,p);
if(d>mid)change(x<<1|1,mid+1,b,c,d,p);
up(x);
}int ask(int x,int a,int b,int c,int d)
inline void makepush(int l,int r,int a,int b)
inline int query(int l,int r)
int main()
for(i=1;i<=m;i++)
} for(cur=0,i=m;i;i--)if(!q[i][0])
for(i=1;i<=n;i++)
for(po[0]=i=1;i<=cur;i++)po[i]=po[i-1]*233;
for(i=1;i<=n;i++)t[i]=ds::build(1,cur,st[i],en[i]);
build(1,1,n-1);
for(i=1;i<=m;i++)if(q[i][0])printf("%d\n",query(q[i][1],q[i][2]));
else makepush(q[i][1],q[i][2],stq[i],enq[i]);
return 0;
}
bzoj3946 無聊的遊戲
並不是一道很無聊的題2333 給定n個串,支援 1.區間在最前面壓入乙個串 2.區間求lcp n 50000,sum 600000 yjc 區間壓串,先考慮區間求lcp,相鄰lcp最小值!故維護區間height最小值mh 區間壓串?對於 l 1,r mh都加上len l,r 1要hei不知道怎麼變 ...
A 無聊的遊戲
應該是博弈論 但我還沒學 這題有點水。n m a b 1 n是m的倍數 那麼這種情況下取的人贏了 2 接下來我們考慮一下走到哪部就穩操勝券了 首先你必須取 m個或者大於m並且是m的倍數,那麼我們考慮2m個特殊邊界,n 2m 舉個例子n 2.5m 我只要取到1.5m 換你取 1.5m m 你必須要取m...
JZOJ 3871 無聊的遊戲
學校的運動會開始了,體能很菜的小可可沒報任何比賽專案,於是和同學們玩乙個十分無聊的遊戲。遊戲在乙個由n n個方格組成的正方形棋盤上進行,首先在每個方格上均勻隨機地填入1到m之間的正整數 每個方格填的數均不同 然後小可可均勻隨機地選出k個1到m的數字 可能選的數不在棋盤上 把它們出現在棋盤上的方格塗黑...