BZOJ1014 JSOI2008 火星人prefix HASH+平衡树+二分法
题意:给定一个字符串,维护:1、修改某个位置的字符 2、查询从p、q位置开始相同字串的长度 3、在某个位置后面插入一个字符
题解:因为需要支持修改所以很容易想到用平衡树,每个节点维护该节点子树所构成的字串的Hash值,修改和插入不用多说,查询我们二分答案,然后在Splay上查询即可。
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define ll long long const int P=233; const int MAXL=100000+2; typedef struct NODE{ int v,c,h; NODE *child[2],*f; NODE(){} NODE(int _v):v(_v),c(1),h(_v){} } *TREE; TREE root,Null; int Q,U,pow[MAXL]; char S[MAXL]; TREE NewNode(TREE f,int v){ TREE x=new NODE(v); x->f=f,x->child[0]=x->child[1]=Null; return x; } void Initilizer(){ Null=NewNode(0,0),Null->c=0; root=NewNode(Null,0); root->child[1]=NewNode(root,0); } void Pushup(TREE &x){ x->c=x->child[0]->c+x->child[1]->c+1; x->h=x->child[0]->h+pow[x->child[0]->c]*x->v+pow[x->child[0]->c+1]*x->child[1]->h; } void Rotate(TREE &x,bool t){ TREE y=x->f; y->child[!t]=x->child[t],x->child[t]->f=y,x->f=y->f; if(y->f->child[0]==y) y->f->child[0]=x; else y->f->child[1]=x; y->f=x,x->child[t]=y; Pushup(y),Pushup(x); if(root==y) root=x; } void Splay(TREE &x,TREE &y){ while(x->f!=y) if(x->f->f==y) if(x->f->child[0]==x) Rotate(x,1); else Rotate(x,0); else if(x->f->f->child[0]==x->f) if(x->f->child[0]==x) Rotate(x->f,1),Rotate(x,1); else Rotate(x,0),Rotate(x,1); else if(x->f->child[0]==x) Rotate(x,1),Rotate(x,0); else Rotate(x->f,0),Rotate(x,0); } void Build(char *S,int L){ TREE x,y; x=y=NewNode(Null,S[0]-'a'+1); for(int i=1;i<L;i++) y=y->child[1]=NewNode(y,S[i]-'a'+1); root->child[1]->child[0]=x,x->f=root->child[1]; Splay(y,Null); } void Select(TREE &x,int p){ TREE y=root; while(y->child[0]->c+1!=p) if(y->child[0]->c>=p) y=y->child[0]; else p-=y->child[0]->c+1,y=y->child[1]; Splay(y,x); } int Find(int p,int x){ Select(Null,p),Select(root,p+x+1); Pushup(root->child[1]->child[0]); return root->child[1]->child[0]->h; } int Query(int x,int y){ int l=1,r=U-y+1,m=(l+r)>>1; while(l<=r){ if(Find(x,m)==Find(y,m)) l=m+1; else r=m-1; m=(l+r)>>1; } if(l>U-y+1 || Find(x,l)!=Find(y,l)) l--; return l; } void Rewrite(int p,int v){ Select(Null,p),Select(root,p+2); root->child[1]->child[0]->v=v,Pushup(root->child[1]->child[0]); } void Insert(int p,int v){ U++,Select(Null,p+1),Select(root,p+2); root->child[1]->child[0]=NewNode(root->child[1],v); Pushup(root->child[1]),Pushup(root); } int main(){ Initilizer(); pow[0]=1; for(int i=1;i<=MAXL;i++) pow[i]=pow[i-1]*P; scanf("%s",S),U=strlen(S); Build(S,U); scanf("%d",&Q); for(int i=1,x,y;i<=Q;i++){ scanf("%s %d",S,&x); if(S[0]=='Q'){ scanf("%d",&y); printf("%d\n",Query(x,y)); } if(S[0]=='R'){ scanf("%s",S); Rewrite(x,S[0]-'a'+1); } if(S[0]=='I'){ scanf("%s",S); Insert(x,S[0]-'a'+1); } } return 0; }