bzoj 1014 火星人prefix —— splay+hash
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014
用 splay 维护字符串上不同位置的哈希值还是第一次...
具体就是每个节点作为位置被不断旋转,点上维护的哈希值就是此时它及其儿子这一段区间的哈希值;
要查询 LCQ,可以二分一个长度,然后把两端区间分别旋转到根,取出哈希值比较;
据说用模数会很慢,写自然溢出比较好;
因为忘记 rotate 最后要 pushup 而调了很久...注释里是另一种可以A的 rotate - splay 系列;
又加深了对 splay 的理解,它的节点表示位置关系...
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define mid ((l+r)>>1) using namespace std; typedef unsigned long long ll; int const xn=1e5+5,xm=250005; int n,m,rt,fa[xm],c[xm][2],siz[xm]; ll pw[xm],hsh[xm]; char s[xn],ch[xn]; void pushup(int x) { int ls=c[x][0],rs=c[x][1]; siz[x]=siz[ls]+siz[rs]+1; hsh[x]=hsh[ls]*pw[siz[rs]+1]+(s[x]-'a'+1)*pw[siz[rs]]+hsh[rs]; } void rotate(int x,int &f) { int y=fa[x],z=fa[y],d=(c[y][1]==x); if(z)c[z][c[z][1]==y]=x; // if(y==f)f=x; else c[z][c[z][1]==y]=x; fa[x]=z; fa[y]=x; fa[c[x][!d]]=y; c[y][d]=c[x][!d]; c[x][!d]=y; pushup(y); pushup(x);//!!! } void splay(int x,int f)// { while(fa[x]!=f)// { int y=fa[x],z=fa[y]; if(z!=f)// { if((c[y][0]==x)^(c[z][0]==y))rotate(x,f); else rotate(y,f); } rotate(x,f); } if(!f)rt=x; } void build(int l,int r,int lst) { if(l>r)return; if(l==r)hsh[l]=s[l]-'a'+1,siz[l]=1; else build(l,mid-1,mid),build(mid+1,r,mid); fa[mid]=lst; c[lst][mid>lst]=mid; pushup(mid); } int find(int x,int k)//找到 k 位置 { while(1) { int p=c[x][0],q=c[x][1]; if(siz[p]+1==k)return x; else if(siz[p]+1<k)x=q,k-=siz[p]+1; else x=p; } } void insert(int pos,char d) { s[++n]=d; hsh[n]=d-'a'+1; int x=find(rt,pos+1);//+1 因为有左右的'a' splay(x,0); x=find(rt,pos+2); splay(x,rt);// // splay(x,rt); x=find(rt,pos+2); splay(x,c[rt][1]); c[x][0]=n; siz[n]=1; fa[n]=x; pushup(x); pushup(rt); } void change(int pos,char d) { int x=find(rt,pos+1); splay(x,0);// // splay(x,rt); s[x]=d; pushup(x); } bool ck(int l,int r,int k) { ll h1=0,h2=0; // int x=find(rt,l); splay(x,rt);// // x=find(rt,l+k+1); splay(x,c[rt][1]); // x=c[rt][1];// int x=find(rt,l); splay(x,0); x=find(rt,l+k+1); splay(x,rt); h1=hsh[c[x][0]]; // x=find(rt,r); splay(x,rt);// // x=find(rt,r+k+1); splay(x,c[rt][1]); // x=c[rt][1];// x=find(rt,r); splay(x,0); x=find(rt,r+k+1); splay(x,rt); h2=hsh[c[x][0]]; return h1==h2; } int query(int x,int l,int r) { int ll=0,rr=n-2-max(l,r)+1,ret=0; while(ll<=rr) { int md=((ll+rr)>>1); if(ck(l,r,md))ret=md,ll=md+1; else rr=md-1; } return ret; } void init() { n=strlen(s+2); pw[0]=1; for(int i=1;i<=xm-5;i++)pw[i]=pw[i-1]*27; s[1]=s[n+2]='a'; build(1,n+2,0); n=n+2; rt=(n+1)/2;// } int main() { scanf("%s",s+2); init(); scanf("%d",&m); for(int i=1,x,y;i<=m;i++) { scanf("%s%d",ch,&x); if(ch[0]=='I')scanf("%s",ch),insert(x,ch[0]); if(ch[0]=='R')scanf("%s",ch),change(x,ch[0]); if(ch[0]=='Q')scanf("%d",&y),printf("%d\n",query(rt,x,y)); } return 0; }