BZOJ 1014 JSOI2008 火星人prefix Splay+Hash+二分
题目大意:给定一个字符串。提供下列操作:
1.查询从x開始的后缀和从y開始的后缀的最长公共前缀长度
2.将x位置的字符改动为y
3.在x位置的字符后面插入字符y
看到这题一開始我先懵住了。
。
。这啥。
。我第一时间想到的是后缀数据结构 可是不会写 并且后缀数据结构也不支持改动操作
后来无奈找了题解才知道是Hash+二分。。
。 太强大了 Hash+二分打爆一切啊
用Splay维护这个字符串的改动和插入操作 每一个节点维护子串的Hash值 推断时二分找到最长公共前缀
只是这道题另一些注意事项
1.此题不卡Hash 不会出现ABBABAABBAABABBA之类恶心字符串
2.题目没有明说 可是字符串上全部字符都是小写字母
3.二分时注意上界的取值 不能超过字符串长度 此题不保证x<y 一定要特判 否则就会RE
剩下就非常裸了、、、80%达成 能够补个番了0.0
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 100100 using namespace std; typedef unsigned long long ll; struct abcd{ abcd *fa,*ls,*rs; int num,siz;ll hash; abcd(int x); void Push_Up(); }*null=new abcd(0),*root=null; abcd :: abcd(int x) { fa=ls=rs=null; num=x;siz=x?1:0;hash=x; } ll ksm[M]; void abcd :: Push_Up() { siz=ls->siz+rs->siz+1; hash=ls->hash*ksm[rs->siz+1]+num*ksm[rs->siz]+rs->hash; } void Zig(abcd *x) { abcd *y=x->fa; y->ls=x->rs; x->rs->fa=y; x->rs=y; x->fa=y->fa; if(y==y->fa->ls) y->fa->ls=x; else if(y==y->fa->rs) y->fa->rs=x; y->fa=x; y->Push_Up(); if(y==root) root=x; } void Zag(abcd *x) { abcd *y=x->fa; y->rs=x->ls; x->ls->fa=y; x->ls=y; x->fa=y->fa; if(y==y->fa->ls) y->fa->ls=x; else if(y==y->fa->rs) y->fa->rs=x; y->fa=x; y->Push_Up(); if(y==root) root=x; } void Splay(abcd *x,abcd *Tar) { while(1) { abcd *y=x->fa,*z=y->fa; if(y==Tar) break; if(z==Tar) { if(x==y->ls) Zig(x); else Zag(x); break; } if(x==y->ls) { if(y==z->ls) Zig(y); Zig(x); } else { if(y==z->rs) Zag(y); Zag(x); } } x->Push_Up(); } void Find(abcd *x,int y,abcd *z) { while(1) { if(y<=x->ls->siz) x=x->ls; else { y-=x->ls->siz; if(y==1) break; y--; x=x->rs; } } Splay(x,z); } char s[M]; void Build_Tree(abcd *&x,int l,int r) { if(l>r) return ; int mid=l+r>>1; x=new abcd(s[mid]-'a'+1); Build_Tree(x->ls,l,mid-1); Build_Tree(x->rs,mid+1,r); x->ls->fa=x; x->rs->fa=x; x->Push_Up(); } void Initialize() { int i; ksm[0]=1; for(i=1;i<=100010;i++) ksm[i]=ksm[i-1]*31; scanf("%s",s); root=new abcd(19980402); root->rs=new abcd(19980402); Build_Tree(root->rs->ls,0,strlen(s)-1); root->rs->ls->fa=root->rs; root->rs->fa=root; root->rs->Push_Up(); root->Push_Up(); } bool Judge(int x,int y,int ans) { Find(root,x,null); Find(root,x+ans+1,root); ll hash1=root->rs->ls->hash; Find(root,y,null); Find(root,y+ans+1,root); ll hash2=root->rs->ls->hash; return hash1==hash2; } int Query(int x,int y) { int l=0,r=root->siz-2-max(x,y)+1; while(l+1<r) { int mid=l+r>>1; if( Judge(x,y,mid) ) l=mid; else r=mid; } if( Judge(x,y,r) ) return r; return l; } int m; int main() { int i,x,y; char p[10]; Initialize(); cin>>m; for(i=1;i<=m;i++) { scanf("%s",p); if(p[0]=='R') { scanf("%d%s",&x,p); Find(root,x+1,null); root->num=p[0]-'a'+1; root->Push_Up(); } else if(p[0]=='I') { scanf("%d%s",&x,p); Find(root,x+1,null); Find(root,x+2,root); root->rs->ls=new abcd(p[0]-'a'+1); root->rs->ls->fa=root->rs; root->rs->Push_Up(); root->Push_Up(); } else scanf("%d%d",&x,&y),printf("%d\n", Query(x,y) ); } }