[BZOJ1014][JSOI2008]火星人prefix splay+hash+二分
Posted halfrot
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1014][JSOI2008]火星人prefix splay+hash+二分相关的知识,希望对你有一定的参考价值。
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1014
先考虑如果没有修改操作和插入操作,是一个静态的字符串,我们可以怎样快速求得题目中的LCQ。
两个字符串判等很容易想到hash。于是我们二分答案并二分判断,就可以在$log_n$时间内得到答案。
现在加上修改和插入操作,其实就是要动态维护子串也就是一段区间的hash值,这种问题很容易就想到用splay来维护。
每个节点记录此节点管辖下子树的hash值h,当前节点的h=左孩子的h+节点的值*seed^{左孩子的size}+右孩子*seed^{左孩子的size+1}
提取子串的hash值就是$log_n$的,时间复杂度$O(nlog_n^2)$
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 const ll seed=233; 7 int inline readint(){ 8 int Num;char ch; 9 while((ch=getchar())<‘0‘||ch>‘9‘);Num=ch-‘0‘; 10 while((ch=getchar())>=‘0‘&&ch<=‘9‘) Num=Num*10+ch-‘0‘; 11 return Num; 12 } 13 void outint(int x){ 14 if(x>=10) outint(x/10); 15 putchar(x%10+‘0‘); 16 } 17 int ch[100010][2],fa[100010],siz[100010],cnt=0,Rt=0,len=0; 18 char val[100010]; 19 ll h[100010],pow[100010]; 20 void Pushup(int &rt){ 21 siz[rt]=siz[ch[rt][0]]+siz[ch[rt][1]]+1; 22 h[rt]=h[ch[rt][0]]+val[rt]*pow[siz[ch[rt][0]]]+h[ch[rt][1]]*pow[siz[ch[rt][0]]+1]; 23 } 24 int Rot(int x,int p){ 25 int y=fa[x],z=fa[y]; 26 fa[ch[x][!p]]=y;ch[y][p]=ch[x][!p]; 27 fa[x]=z;if(z) ch[z][ch[z][1]==y]=x; 28 fa[y]=x;ch[x][!p]=y; 29 Pushup(y);Pushup(x); 30 } 31 void Splay(int x,int T){ 32 while(fa[x]!=T){ 33 if(fa[fa[x]]==T) Rot(x,ch[fa[x]][1]==x); 34 else{ 35 int y=fa[x],z=fa[y],p=ch[z][1]==y; 36 if(ch[y][p]==x) Rot(y,p),Rot(x,p); 37 else Rot(x,!p),Rot(x,p); 38 } 39 } 40 if(!T) Rt=x; 41 } 42 void Find(int k,int t){ 43 int x=Rt,tmp; 44 while(x){ 45 tmp=siz[ch[x][0]]; 46 if(k==tmp+1){ 47 Splay(x,t); 48 return; 49 } 50 else if(k<tmp+1) x=ch[x][0]; 51 else{ 52 k-=tmp+1; 53 x=ch[x][1]; 54 } 55 } 56 } 57 char s[100010]; 58 int Build(int l,int r){ 59 if(l>r) return 0; 60 int mid=l+r>>1,rt=++cnt; 61 val[rt]=s[mid]; 62 ch[rt][0]=Build(l,mid-1); 63 if(ch[rt][0]) fa[ch[rt][0]]=rt; 64 ch[rt][1]=Build(mid+1,r); 65 if(ch[rt][1]) fa[ch[rt][1]]=rt; 66 Pushup(rt); 67 return rt; 68 } 69 void Lcq(int x,int y){ 70 int l=1,r=len,mid,ans=0; 71 ll tmp; 72 while(l<=r){ 73 mid=l+r>>1; 74 if(y+mid>len+1) r=mid-1; 75 else{ 76 Find(x,0); 77 Find(x+mid+1,Rt); 78 tmp=h[ch[ch[Rt][1]][0]]; 79 Find(y,0); 80 Find(y+mid+1,Rt); 81 if(tmp==h[ch[ch[Rt][1]][0]]){ 82 ans=mid; 83 l=mid+1; 84 } 85 else r=mid-1; 86 } 87 } 88 outint(ans); 89 putchar(‘\n‘); 90 } 91 int main(){ 92 pow[0]=1;for(int i=1;i<=100000;i++) pow[i]=pow[i-1]*seed; 93 siz[0]=h[0]=fa[0]=ch[0][0]=ch[0][1]=0; 94 scanf("%s",s+1); 95 len=strlen(s+1); 96 Rt=Build(0,len+1); 97 int m,x,y; 98 scanf("%d",&m); 99 char opt[5],tmp[5]; 100 while(m--){ 101 scanf("%s",opt); 102 switch(opt[0]){ 103 case ‘R‘: 104 scanf("%d%s",&x,tmp); 105 Find(x+1,0); 106 val[Rt]=tmp[0]; 107 Pushup(Rt); 108 break; 109 case ‘I‘: 110 scanf("%d%s",&x,tmp); 111 Find(x+1,0); 112 Find(x+2,Rt); 113 val[++cnt]=tmp[0]; 114 fa[cnt]=ch[Rt][1]; 115 ch[ch[Rt][1]][0]=cnt; 116 Pushup(cnt); 117 Pushup(ch[Rt][1]); 118 Pushup(Rt); 119 len++; 120 break; 121 case ‘Q‘: 122 scanf("%d%d",&x,&y); 123 if(x>y) swap(x,y); 124 Lcq(x,y); 125 break; 126 } 127 } 128 }
以上是关于[BZOJ1014][JSOI2008]火星人prefix splay+hash+二分的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
[BZOJ1014][JSOI2008]火星人prefix splay+二分+hash
[BZOJ]1014 火星人prefix(JSOI2008)