题目链接
题意:一个长度为n的01串(n<=200000),m次操作,操作包括在某个位置添加一个字符,删除某个位置的字符,翻转某个区间的字符串,询问两个后缀的LCP。
题解:对于一个静态的字符串,询问其两个后缀的最长LCP,可以用hash+二分的方法,O(lgn)的复杂度求解一次询问。
此题对字符串有添加、删除和区间的翻转的操作,所以我们考虑用splay维护串的hash值。
具体而言,我们维护以这个点为根的子树的点的个数和对应串的hash值。对于区间翻转操作而言,仅仅维护这些值是不行的,我还要维护以这个点为根的子树的翻转串的hash值。
详情见代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<math.h> #include<queue> #include<stack> #include<set> #include<map> #include<vector> #include<string.h> #include<string> #include<stdlib.h> typedef long long LL; typedef unsigned long long LLU; const int nn=410000; const int inf=0x3fffffff; const LL inf64=(LL)inf*inf; const int mod=1000000007; using namespace std; int n,m; LL po[nn]; char s[nn]; struct node { int val; int cnt; LL ha; LL fha; bool fz; node* pre; node* ch[2]; }*root; void init() { po[0]=1; for(int i=1;i<=400010;i++) { po[i]=(po[i-1]*2)%mod; } root=NULL; root=new node; root->val=0; root->cnt=2; root->fz=false; root->ha=root->fha=0; root->pre=NULL; root->ch[0]=root->ch[1]=NULL; root->ch[1]=new node; root->ch[1]->val=0; root->ch[1]->cnt=1; root->ch[1]->fz=false; root->ch[1]->ha=root->ch[1]->fha=0; root->ch[1]->pre=root; root->ch[1]->ch[0]=root->ch[1]->ch[1]=NULL; } inline void push_up(node* o) { o->cnt=1; int lson,rson; lson=rson=0; LL lha,rha,lfha,rfha; lha=rha=lfha=rfha=0; if(o->ch[0]!=NULL) { lha=o->ch[0]->ha; lfha=o->ch[0]->fha; o->cnt+=o->ch[0]->cnt; lson+=o->ch[0]->cnt; } if(o->ch[1]!=NULL) { rha=o->ch[1]->ha; rfha=o->ch[1]->fha; o->cnt+=o->ch[1]->cnt; rson+=o->ch[1]->cnt; } o->ha=lha+(o->val*po[lson])%mod+(rha*po[lson+1])%mod; o->ha%=mod; o->fha=rfha+(o->val*po[rson])%mod+(lfha*po[rson+1])%mod; o->fha%=mod; } inline void push_down(node* o) { if(o->fz) { o->fz=false; if(o->ch[0]!=NULL) { o->ch[0]->fz=!o->ch[0]->fz; swap(o->ch[0]->ha,o->ch[0]->fha); swap(o->ch[0]->ch[0],o->ch[0]->ch[1]); } if(o->ch[1]!=NULL) { o->ch[1]->fz=!o->ch[1]->fz; swap(o->ch[1]->ha,o->ch[1]->fha); swap(o->ch[1]->ch[0],o->ch[1]->ch[1]); } } } void Rotate(node* o) { node* x=o->pre; // push_down(x); // push_down(o); int d=(x->ch[0]==o)?0:1; x->ch[d]=o->ch[d^1]; if(o->ch[d^1]!=NULL) { o->ch[d^1]->pre=x; } if(x->pre!=NULL) { if(x->pre->ch[0]==x) x->pre->ch[0]=o; else x->pre->ch[1]=o; } o->pre=x->pre; o->ch[d^1]=x; x->pre=o; push_up(x); } void Splay(node* o,node* f) { node* x; node* y; while(o->pre!=f) { if(o->pre->pre==f) Rotate(o); else { x=o->pre; y=x->pre; int d1=(y->ch[0]==x)?0:1; int d2=(x->ch[0]==o)?0:1; if(d1==d2) { Rotate(x); Rotate(o); } else { Rotate(o); Rotate(o); } } } push_up(o); if(f==NULL) root=o; } void select(int k,node* f) { node* o=root; int tem; while(k) { push_down(o); tem=0; if(o->ch[0]!=NULL) tem+=o->ch[0]->cnt; if(tem>=k) o=o->ch[0]; else if(tem+1==k) break; else { o=o->ch[1]; k-=tem+1; } } Splay(o,f); } void build(node* &o,node* f,int l,int r) { int mid=(l+r)/2; o=new node; o->val=s[mid]-'0'; o->cnt=1; o->ha=o->fha=o->val; o->fz=false; o->pre=f; o->ch[0]=o->ch[1]=NULL; if(l<=mid-1) { build(o->ch[0],o,l,mid-1); } if(mid+1<=r) { build(o->ch[1],o,mid+1,r); } push_up(o); } void add(int id,int val) { select(id+1,NULL); select(id+2,root); root->ch[1]->ch[0]=new node; root->ch[1]->ch[0]->val=val; root->ch[1]->ch[0]->cnt=1; root->ch[1]->ch[0]->ha=root->ch[1]->ch[0]->fha=val; root->ch[1]->ch[0]->fz=false; root->ch[1]->ch[0]->pre=root->ch[1]; root->ch[1]->ch[0]->ch[0]=root->ch[1]->ch[0]->ch[1]=NULL; Splay(root->ch[1]->ch[0],NULL); } void san(int id) { select(id,NULL); select(id+2,root); delete root->ch[1]->ch[0]; root->ch[1]->ch[0]=NULL; Splay(root->ch[1],NULL); } void Reverse(int l,int r) { select(l,NULL); select(r+2,root); node* &o=root->ch[1]->ch[0]; o->fz=!o->fz; swap(o->ha,o->fha); swap(o->ch[0],o->ch[1]); push_down(o); Splay(o,NULL); } bool check(int len,int L,int R) { select(L,NULL); select(L+len+1,root); LL ix=root->ch[1]->ch[0]->ha; select(R,NULL); select(R+len+1,root); LL fc=root->ch[1]->ch[0]->ha; return ix==fc; } int solve(int L,int R) { int l=0,r=root->cnt-1-R; int mid; while(l<r) { mid=(l+r+1)/2; if(check(mid,L,R)) l=mid; else r=mid-1; } return l; } void Clear(node* &o) { if(o==NULL) return ; Clear(o->ch[0]); Clear(o->ch[1]); delete o; o=NULL; } int main() { init(); int ix,p1,p2; while(scanf("%d%d",&n,&m)!=EOF) { scanf("%s",s); select(1,NULL); build(root->ch[1]->ch[0],root->ch[1],0,n-1); Splay(root->ch[1]->ch[0],NULL); while(m--) { scanf("%d",&ix); if(ix==1) { scanf("%d%d",&p1,&p2); add(p1,p2); } else if(ix==2) { scanf("%d",&p1); san(p1); } else if(ix==3) { scanf("%d%d",&p1,&p2); Reverse(p1,p2); } else { scanf("%d%d",&p1,&p2); printf("%d\n",solve(p1,p2)); } } select(1,NULL); select(root->cnt,root); Clear(root->ch[1]->ch[0]); Splay(root->ch[1],NULL); } return 0; }