题意:
给出一个字符串,多次查询它的LCQ(最长公共前缀)(这个‘Q‘是‘前‘的意思吗!= = )
带修改以及插入;
长度<=100000,操作<=100000;
题解:
这题刚学Splay的时候就听说过的题;
然而当时不知道啥是RKhash就弃疗了;
现在复习一下顺便清一下BZ第一版;
利用hash+二分处理最长公共前缀是基础;
然后就是在Splay上动态维护hash值;
具体维护就是记录每个结点的字符,每次Pushup的时候乘上进制的幂次再与左子树的加和,右子树同理;
旋转啥的注意一下Pushup的时机就好;
查询的时候每次二分都将区间提取出来一下,然后判断是否相同;
这样每次是logn,二分也是logn,时间复杂度最大在O(mlog^2n);
注意如果为了方便在首尾都加了结点的话,判断x==y的时候可能会多算一个末尾;
但是特判一下x==y也就结束了;
我本来是能1A这题的。。。然而因为水轮状病毒上Python所以CE了一发。。好蠢。。。
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 140142 #define seed 131 #define which(x) (ch[fa[x]][1]==x) using namespace std; typedef unsigned long long ll; char str[N],op[10],val[10]; int fa[N],ch[N][2],size[N],n,root,tot; ll hash[N],pow[N]; char s[N]; void Pushup(int x) { size[x]=size[ch[x][0]]+size[ch[x][1]]+1; hash[x]=hash[ch[x][0]]+pow[size[ch[x][0]]]*s[x]+pow[size[ch[x][0]]+1]*hash[ch[x][1]]; } void Rotate(int x) { int f=fa[x]; bool k=which(x); ch[f][k]=ch[x][!k]; ch[x][!k]=f; ch[fa[f]][which(f)]=x; fa[ch[f][k]]=f; fa[x]=fa[f]; fa[f]=x; size[x]=size[f],hash[x]=hash[f]; Pushup(f); } void Splay(int x,int g) { while(fa[x]!=g) { int f=fa[x]; if(fa[f]==g) { Rotate(x); break; } if(which(x)^which(f)) Rotate(x); else Rotate(f); Rotate(x); } if(!g) root=x; } int Rank(int x,int k) { if(k<=size[ch[x][0]]) return Rank(ch[x][0],k); else if(k==size[ch[x][0]]+1) return x; else return Rank(ch[x][1],k-size[ch[x][0]]-1); } int Build(int l,int r,int f) { if(l>r) return 0; int x=++tot,mid=l+r>>1; fa[x]=f,s[x]=str[mid]; ch[x][0]=Build(l,mid-1,x); ch[x][1]=Build(mid+1,r,x); Pushup(x); return x; } void Insert(int k,char val) { int x=Rank(root,k),y=Rank(root,k+1); Splay(x,0),Splay(y,x); s[++tot]=val; fa[tot]=y,ch[y][0]=tot; Pushup(tot); Pushup(y); Pushup(x); } void Change(int k,char val) { int x=Rank(root,k); Splay(x,0); s[x]=val; Pushup(x); } int LCQ(int kx,int ky) { int l=0,r=n,mid; while(l<=r) { mid=l+r>>1; if(ky+mid>n+2) { r=mid-1; continue; } int x=Rank(root,kx-1),y=Rank(root,kx+mid); Splay(x,0),Splay(y,x); ll temp=hash[ch[y][0]]; x=Rank(root,ky-1),y=Rank(root,ky+mid); Splay(x,0),Splay(y,x); if(temp==hash[ch[y][0]]) l=mid+1; else r=mid-1; } return r; } int main() { int m,i,j,k,x,y; scanf("%s%d",str+1,&m); n=strlen(str+1); for(pow[0]=1,i=1;i<N;i++) pow[i]=pow[i-1]*seed; root=Build(0,n+1,0); for(i=1;i<=m;i++) { scanf("%s",op); if(op[0]=='I') { scanf("%d%s",&x,val); Insert(x+1,val[0]); n++; } else if(op[0]=='R') { scanf("%d%s",&x,val); Change(x+1,val[0]); } else { scanf("%d%d",&x,&y); if(x>y) swap(x,y); if(x!=y) printf("%d\n",LCQ(x+1,y+1)); else printf("%d\n",n-x+1); } } return 0; }
原文地址:http://blog.csdn.net/ww140142/article/details/47607625