本题目的操作是维护01序列。
并需要动态比较序列当前任意两个位置后缀的LCP。
那么只需要用splay维护序列的同时,再维护一个域(当前所在子树01序列的hash值),查找时就可以用伸展树的分裂和合并操作提取所需子树hash值,然后二分即可。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstring> #include <algorithm> #include <cstdio> #include <iostream> using namespace std; typedef long long ll; typedef unsigned long long llu; #define rep1(i,x,y) for(int i=x;i<=y;i++) #define rep(i,n) for(int i=0;i<(int)n;i++) const int maxn = 5e5 + 100; const llu base = 3137; llu BA[maxn]; typedef struct node* pointer; struct node{ pointer ch[2]; int c,flip,v; llu ha[2]; node(int v=0):v(v){c = 1 ; ha[0]=ha[1]=v; ch[1]=ch[0]=NULL; flip=0;} int cl(){return ch[0]==NULL ? 0 : ch[0]->c;} int cr(){return ch[1]==NULL ? 0 : ch[1]->c;} llu hal(int d){ return ch[0]==NULL ? 0:ch[0]->ha[d];} llu har(int d){ return ch[1]==NULL ? 0:ch[1]->ha[d];} int cmp(int x){ if(x == cl() + 1) return -1; return(cl()>=x ? 0 : 1); } void maintain(){ if(ch[0]!=NULL) ch[0]->pushdown(); if(ch[1]!=NULL) ch[1]->pushdown(); ha[0] = (hal(0)*base + v)*BA[cr()] + har(0); ha[1] = (har(1)*base + v)*BA[cl()] + hal(1); c = 1 + cl() + cr(); } void pushdown(){ if(flip){ flip^=1; swap(ch[0],ch[1]); swap(ha[0],ha[1]); if(ch[0]!=NULL) ch[0]->flip^=1; if(ch[1]!=NULL) ch[1]->flip^=1; } } }; void rotate(pointer& u,int d){ pointer te = u->ch[d^1]; u->ch[d^1] = te->ch[d]; te->ch[d] = u; u->maintain(); te->maintain(); u = te; } void splay(pointer& u,int k){ u->pushdown(); int d = u->cmp(k); if(d!=-1){ int k2 = (u->cl()>=k ? k : k-u->cl()-1); pointer te = u->ch[d]; te->pushdown(); int d2 = te->cmp(k2); if(d2!=-1){ splay(te->ch[d2],d2==0 ? k2 : k2-te->cl()-1); if(d2 == d) rotate(u , d^1); else rotate(u->ch[d],d2^1); } rotate(u , d^1); } } void split(pointer u ,int k , pointer& le ,pointer& ri){ splay(u,k); le = u; ri = le->ch[1]; le->ch[1] = NULL; le->maintain(); } pointer merge_(pointer le , pointer ri){ splay(le,le->c); le->ch[1] = ri; le->maintain(); return le; } pointer insert_(pointer u , int p,int v){ pointer le,ri; split(u,p,le,ri); le->ch[1]=new node(v); le->maintain(); return merge_(le,ri); } pointer erase_(pointer u, int p){ pointer le,ri; split(u,p,le,ri); pointer te = le; le=le->ch[0]; delete te; return merge_(le,ri); } pointer flip_(pointer u,int p1,int p2){ pointer le,mid,ri,te; split(u,p1,le,te); split(te,p2-p1+1,mid,ri); mid->flip^=1; return merge_(merge_(le,mid),ri); } llu cal(pointer& u,int len,int p){ pointer le,mid,ri,te; split(u,p,le,te); split(te,len,mid,ri); llu tte = mid->ha[0]; u = merge_(merge_(le,mid),ri); return tte; } int judge(pointer& u, int len,int p1,int p2){ return (cal(u,len,p1)==cal(u,len,p2)); } int find_(pointer& u ,int p1,int p2){ int n = u->c-1; int l=1,r=n-max(p1,p2)+1; if(judge(u,r,p1,p2)) return r; while(l<r){ int m=(l+r)>>1; if(judge(u,m,p1,p2)) l=m+1; else r=m; } return l-1; } int n,Q; char str[maxn]; pointer root; void show(pointer u){ u->pushdown(); if(u == NULL) return ; show(u->ch[0]); printf("%d",u->v); show(u->ch[1]); } void del(pointer& u){ if(u==NULL) return ; del(u->ch[0]); del(u->ch[1]); delete u; u = NULL; } int main() { BA[0] = 1; rep1(i,1,maxn-1) BA[i]=BA[i-1]*base; while(scanf("%d %d",&n,&Q)==2){ scanf("%s",str); del(root); root=NULL; for(int i=n-1;i>=0;i--) { pointer te=new node(str[i]-'0'); te->ch[1]=root; root = te; root->maintain(); } pointer te=new node(0); te->ch[1]=root; root = te; root->maintain(); while(Q--){ int cmd,p1,p2; scanf("%d %d",&cmd,&p1); if(cmd!=2) scanf("%d",&p2); if(cmd==1){ p1++; root = insert_(root,p1,p2); } else if(cmd==2){ p1++; root = erase_(root,p1); } else if(cmd==3){ root=flip_(root,p1,p2); } else { int ans = find_(root,p1,p2); printf("%d\n",ans); } } } return 0; } /* 3 10 000 2 1 2 1 2 1 1 0 1 */