给一个长度为n的01串,m个操作:
1 p c :在第p位之后插入字符
2 p :删除第p位字符
3 p1 p2: 把从p1到p2位之间的字符翻转
4 p1 p2: 查询以p1,p2开始的字符串的最长公共前缀。
前三个操作可以直接用伸展树处理,查询lcp的话,可以给在每个节点记录一下该子树表示的字符串的hash值,这样在查询的时候就可以二分长度去求lcp了。
因为涉及到翻转操作,所以要求两个hash值,一个正向一个反向,在翻转的时候,直接交换这两个方向的hash值就行。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> using namespace std; typedef long long ll; typedef unsigned long long ull; const ull x=233; const int maxn=502000; int a[maxn],b[maxn]; char s[maxn]; ull H[2][maxn]; ull xp[maxn]; int size[maxn]; int pre[maxn],ch[maxn][2]; int flip[maxn]; int tot,root; int n,m; struct splaytree { void init() { tot=root=0; newnode(root,0,0); newnode(ch[root][1],root,0); build(1,n,ch[ch[root][1]][0],ch[root][1]); pushup(ch[root][1]); pushup(root); } void pushup(int r) { if (r==0) return; size[r]=size[ch[r][0]]+1+size[ch[r][1]]; H[1][r]=H[1][ch[r][0]]*xp[1+size[ch[r][1]]]+a[r]*xp[size[ch[r][1]]]+H[1][ch[r][1]]; H[0][r]=H[0][ch[r][0]]+a[r]*xp[size[ch[r][0]]]+H[0][ch[r][1]]*xp[size[ch[r][0]]+1]; } void go_f(int r) { if (!r) return; flip[r]^=1; swap(H[0][r],H[1][r]); swap(ch[r][0],ch[r][1]); // pushup(r); } void pushdown(int r) { if (flip[r]) { go_f(ch[r][0]); go_f(ch[r][1]); flip[r]=0; } } void rotate(int xx,int kind) { int y=pre[xx]; pushdown(y); pushdown(xx); ch[y][!kind]=ch[xx][kind]; pre[ch[xx][kind]]=y; if (pre[y]) { ch[pre[y]][ch[pre[y]][1]==y]=xx; } pre[xx]=pre[y]; ch[xx][kind]=y; pre[y]=xx; pushup(y); } void splay(int xx,int tgt) { pushdown(xx); while(pre[xx]!=tgt) { int y=pre[xx]; if (pre[pre[xx]]==tgt) { rotate(xx,ch[pre[xx]][0]==xx); } else { int kind=(ch[pre[y]][0]==y); if (ch[y][kind]==xx) { rotate(xx,kind^1); rotate(xx,kind); } else { rotate(y,kind); rotate(xx,kind); } } } pushup(xx); if (tgt==0) root=xx; } void select(int k,int tgt) { int rt=root; pushdown(rt); while(true) { if (k<=size[ch[rt][0]]) rt=ch[rt][0]; else if (k==size[ch[rt][0]]+1) break; else k-=(size[ch[rt][0]]+1),rt=ch[rt][1]; pushdown(rt); } splay(rt,tgt); } void newnode(int &r,int father,int k) { r=++tot; pre[r]=father; size[r]=1; flip[r]=0; a[r]=k; H[0][r]=H[1][r]=k; ch[r][0]=ch[r][1]=0; } void build(int l,int r,int &xx,int rt) { if (l>r) return; int m=(l+r)>>1; newnode(xx,rt,b[m]); build(l,m-1,ch[xx][0],xx); build(m+1,r,ch[xx][1],xx); pushup(xx); pushup(rt); } void insert(int posi,int c) { select(posi+1,0); select(posi+2,root); newnode(ch[ch[root][1]][0],ch[root][1],c); pushup(ch[root][1]); pushup(root); } void del(int posi) { select(posi,0); select(posi+2,root); int k=ch[ch[root][1]][0]; pre[k]=0; ch[ch[root][1]][0]=0; pushup(ch[root][1]); pushup(root); } ull queryHash(int r,int l) { select(r,0); select(r+l+1,root); return H[0][ch[ch[root][1]][0]]; } bool check(int p1,int p2,int l) { if (queryHash(p1,l)==queryHash(p2,l)) return true; return false; } int getlcp(int p1,int p2) { int ans; if (!check(p1,p2,1)) { return 0; } ans=1; int l=1,r=min(size[root]-2-p1+1,size[root]-2-p2+1)+1; int mid; while(l<r) { mid=(l+r)>>1; if (check(p1,p2,mid)) ans=mid,l=mid+1; else r=mid; } return ans; } void reverse(int p1,int p2) { select(p1,0); select(p2+2,root); go_f(ch[ch[root][1]][0]); pushup(ch[root][1]); pushup(root); } void print(int r) { if (r==0) return; pushdown(r); print(ch[r][0]); cout<<a[r]; print(ch[r][1]); } void traval(int x) { if(x) { pushdown(x); traval(ch[x][0]); printf("结点%2d:左儿子 %2d 右儿子 %2d 父节点 %2d size=%2d ,val=%2d, filp=%2d\n",x,ch[x][0],ch[x][1],pre[x],size[x],a[x],flip[x]); traval(ch[x][1]); } } void Debug() { printf("%d\n",root); traval(root); } }spt; void reads(int & x) { char c; bool neg=false; while(((c=getchar())<'0'||c>'9')&&c!='-'); if(c=='-') { neg=true; while((c=getchar())<'0'||c>'9'); } x=c-'0'; while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0'; if(neg) x=-x; } int main() { // freopen("in.txt","r",stdin); xp[0]=1; for (int i=1; i<maxn; i++) xp[i]=xp[i-1]*x; while(~scanf("%d%d",&n,&m)) { scanf("%s",s); for (int i=1; i<=n; i++) b[i]=s[i-1]-'0'; spt.init(); // spt.traval(root); // spt.print(root); // cout<<endl; int cmd,p1,p2,p3,p4; while(m--) { // scanf("%d",&cmd); reads(cmd); if (cmd==1) { // scanf("%d%d",&p1,&p2); reads(p1); reads(p2); spt.insert(p1,p2); } else if (cmd==2) { // scanf("%d",&p1); reads(p1); spt.del(p1); } else if (cmd==3) { // scanf("%d%d",&p1,&p2); reads(p1); reads(p2); spt.reverse(p1,p2); // spt.traval(root); // cout<<p1<<" "<<p2<<endl; // spt.print(root); // cout<<endl; } else if (cmd==4) { // scanf("%d%d",&p1,&p2); reads(p1); reads(p2); printf("%d\n",spt.getlcp(p1,p2)); } } } return 0; }