LCPhash求解
今天学习了一种用hash求解lcp问题的方法。
把一段内的hash表示为某个数x的递增次方乘上字符串相应位置的字母对应值,然后二分长度,判断两段的hash值是否相等就可以了。
hash值可以用unsigned long long保存,这种类型能在溢出的时候自动mod2^64(看到书上说的)。
cogs1849 jsoi火星人prefix
题目大意:对于一个字符串,有修改、插入和查询x、y位置开始的最长公共字串的长度三种操作。
思路:使用这种方法,在fhqTREEP上实现的。(但是常数比较大,所以bzoj上t掉了。。。)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<ctime> #define xx 10007 #define sigmasiz 26 #define maxnode 100005 using namespace std; unsigned long long mi[maxnode]={0}; struct Node{ Node* ch[2]; char cc; int siz,r; unsigned long long hash; Node(char cc):cc(cc){ch[0]=ch[1]=NULL;r=rand();siz=1;hash=(cc-'a')+1;} void updata() { siz=1;hash=0; if (ch[0]!=NULL) { siz+=ch[0]->siz; hash+=ch[0]->hash; } hash+=mi[siz-1]*(cc-'a'+1); if (ch[1]!=NULL) { hash+=ch[1]->hash * mi[siz]; siz+=ch[1]->siz; } } }*root; char ss[maxnode]; int n; Node* merge(Node *aa,Node *bb) { if (aa==NULL) return bb; if (bb==NULL) return aa; if (aa->r < bb->r) { aa->ch[1]=merge(aa->ch[1],bb); if (aa!=NULL) aa->updata(); return aa; } else { bb->ch[0]=merge(aa,bb->ch[0]); if (bb!=NULL) bb->updata(); return bb; } } void split(Node *o,Node* &aa,Node* &bb,int x) { if (o==NULL){aa=bb=NULL;return;} if (x==0){aa=NULL;bb=o;return;} if (x==o->siz){aa=o;bb=NULL;return;} if ((o->ch[0]==NULL ? 0 : o->ch[0]->siz)>=x) { split(o->ch[0],aa,bb,x); o->ch[0]=bb;o->updata();bb=o; } else { split(o->ch[1],aa,bb,x-(o->ch[0]==NULL? 0 : o->ch[0]->siz)-1); o->ch[1]=aa;o->updata();aa=o; } } void change(Node* &o,int x,char c) { Node *a,*b,*y,*z; split(o,a,b,x-1);split(b,y,z,1); y=new Node(c);b=merge(y,z);o=merge(a,b); } void ins(Node* &o,int x,char c) { Node *a,*b,*y,*z; split(o,a,b,x);y=new Node(c); z=merge(a,y);o=merge(z,b);++n; } unsigned long long calc(Node* o,int z,int ll) { Node *a,*b,*x,*y; unsigned long long sum; split(o,a,b,z-1);split(b,x,y,ll); if (x!=NULL) sum=x->hash; else sum=0; b=merge(x,y);o=merge(a,b); return sum; } int ask(Node* o,int x,int y) { Node *a,*b,*p,*q; int l,r,mid,ss; l=0;r=ss=min(n-x+1,n-y+1); while(l<r) { mid=(l+r)/2; if (calc(o,x,ss-mid)==calc(o,y,ss-mid)) r=mid; else l=mid+1; } return ss-l; } int main() { int i,j,m,ll,a,b; char kk,c; mi[0]=1;root=NULL; for (i=1;i<maxnode;++i) mi[i]=mi[i-1]*xx; scanf("%s",&ss);n=strlen(ss); for (i=0;i<n;++i) { Node *o; o=new Node(ss[i]); root=merge(root,o); } scanf("%d",&m); for (i=1;i<=m;++i) { while(kk=getchar()) if (kk>='A'&&kk<='Z') break; if (kk=='Q') { scanf("%d%d",&a,&b); printf("%d\n",ask(root,a,b)); } if (kk=='R') { scanf("%d",&a); while(c=getchar()) if (c>='a'&&c<='z') break; change(root,a,c); } if (kk=='I') { scanf("%d",&a); while(c=getchar()) if (c>='a'&&c<='z') break; ins(root,a,c); } } }
(把unsigned long long改为unsigned int,再加上inline,就从bzoj上a掉了。。。)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<ctime> #define xx 10007 #define sigmasiz 26 #define maxnode 100005 using namespace std; unsigned int mi[maxnode]={0}; struct Node{ Node* ch[2]; char cc; int siz,r; unsigned int hash; Node(char cc):cc(cc){ch[0]=ch[1]=NULL;r=rand();siz=1;hash=(cc-'a')+1;} void updata() { siz=1;hash=0; if (ch[0]!=NULL) { siz+=ch[0]->siz; hash+=ch[0]->hash; } hash+=mi[siz-1]*(cc-'a'+1); if (ch[1]!=NULL) { hash+=ch[1]->hash * mi[siz]; siz+=ch[1]->siz; } } }*root; char ss[maxnode]; int n; inline Node* merge(Node *aa,Node *bb) { if (aa==NULL) return bb; if (bb==NULL) return aa; if (aa->r < bb->r) { aa->ch[1]=merge(aa->ch[1],bb); if (aa!=NULL) aa->updata(); return aa; } else { bb->ch[0]=merge(aa,bb->ch[0]); if (bb!=NULL) bb->updata(); return bb; } } inline void split(Node *o,Node* &aa,Node* &bb,int x) { if (o==NULL){aa=bb=NULL;return;} if (x==0){aa=NULL;bb=o;return;} if (x==o->siz){aa=o;bb=NULL;return;} if ((o->ch[0]==NULL ? 0 : o->ch[0]->siz)>=x) { split(o->ch[0],aa,bb,x); o->ch[0]=bb;o->updata();bb=o; } else { split(o->ch[1],aa,bb,x-(o->ch[0]==NULL? 0 : o->ch[0]->siz)-1); o->ch[1]=aa;o->updata();aa=o; } } inline void change(Node* &o,int x,char c) { Node *a,*b,*y,*z; split(o,a,b,x-1);split(b,y,z,1); y=new Node(c);b=merge(y,z);o=merge(a,b); } inline void ins(Node* &o,int x,char c) { Node *a,*b,*y,*z; split(o,a,b,x);y=new Node(c); z=merge(a,y);o=merge(z,b);++n; } inline unsigned int calc(Node* o,int z,int ll) { Node *a,*b,*x,*y; unsigned int sum; split(o,a,b,z-1);split(b,x,y,ll); if (x!=NULL) sum=x->hash; else sum=0; b=merge(x,y);o=merge(a,b); return sum; } inline int ask(Node* o,int x,int y) { Node *a,*b,*p,*q; int l,r,mid,ss; l=0;r=ss=min(n-x+1,n-y+1); while(l<r) { mid=(l+r)/2; if (calc(o,x,ss-mid)==calc(o,y,ss-mid)) r=mid; else l=mid+1; } return ss-l; } int main() { int i,j,m,ll,a,b; char kk,c; mi[0]=1;root=NULL; for (i=1;i<maxnode;++i) mi[i]=mi[i-1]*xx; scanf("%s",&ss);n=strlen(ss); for (i=0;i<n;++i) { Node *o; o=new Node(ss[i]); root=merge(root,o); } scanf("%d",&m); for (i=1;i<=m;++i) { while(kk=getchar()) if (kk>='A'&&kk<='Z') break; if (kk=='Q') { scanf("%d%d",&a,&b); printf("%d\n",ask(root,a,b)); } if (kk=='R') { scanf("%d",&a); while(c=getchar()) if (c>='a'&&c<='z') break; change(root,a,c); } if (kk=='I') { scanf("%d",&a); while(c=getchar()) if (c>='a'&&c<='z') break; ins(root,a,c); } } }