BZOJ1014:[JSOI2008]火星人(Splay,hash)
Description
火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串:madamimadam,
我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,
火星人定义了一个函数LCQ(x, y),表示:该字符串中第x个字符开始的字串,与该字符串中第y个字符开始的字串
,两个字串的公共前缀的长度。比方说,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0 在研究LCQ函数的过程
中,火星人发现了这样的一个关联:如果把该字符串的所有后缀排好序,就可以很快地求出LCQ函数的值;同样,
如果求出了LCQ函数的值,也可以很快地将该字符串的后缀排好序。 尽管火星人聪明地找到了求取LCQ函数的快速
算法,但不甘心认输的地球人又给火星人出了个难题:在求取LCQ函数的同时,还可以改变字符串本身。具体地说
,可以更改字符串中某一个字符的值,也可以在字符串中的某一个位置插入一个字符。地球人想考验一下,在如此
复杂的问题中,火星人是否还能够做到很快地求取LCQ函数的值。
Input
第一行给出初始的字符串。第二行是一个非负整数M,表示操作的个数。接下来的M行,每行描述一个操作。操
作有3种,如下所示
1、询问。语法:Qxy,x,y均为正整数。功能:计算LCQ(x,y)限制:1<=x,y<=当前字符串长度。
2、修改。语法:Rxd,x是正整数,d是字符。功能:将字符串中第x个数修改为字符d。限制:x不超过当前字
符串长度。
3、插入:语法:Ixd,x是非负整数,d是字符。功能:在字符串第x个字符之后插入字符d,如果x=0,则在字
符串开头插入。限制:x不超过当前字符串长度
Output
对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。
Sample Input
7
Q 1 7
Q 4 8
Q 10 11
R 3 a
Q 1 7
I 10 a
Q 2 11
Sample Output
1
0
2
1
HINT
1、所有字符串自始至终都只有小写字母构成。
2、M<=150,000
3、字符串长度L自始至终都满足L<=100,000
4、询问操作的个数不超过10,000个。
对于第1,2个数据,字符串长度自始至终都不超过1,000
对于第3,4,5个数据,没有插入操作。
Solution
用splay维护hash值
当前点update的时候就用俩儿子的hash值计算一下字符串(左儿子+x+右儿子)新的hash值
hash一开始被卡了素质三连(模数1e4+7不被卡就有鬼了……)
中途有个变量打错了还过了样例emmm……
喜闻乐见样例是有多弱
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (200000+100) 5 #define MOD (19260817) 6 using namespace std; 7 int Val[N],Size[N],Son[N][2],Father[N],Sum[N],hash[N]; 8 int Root,n,m,x,y,p,sz; 9 char opt[15],ch[15],a[N]; 10 11 int Get(int x) {return Son[Father[x]][1]==x;} 12 void Clear(int x) {Sum[x]=Father[x]=Son[x][0]=Son[x][1]=Size[x]=Val[x]=0;} 13 14 void Update(int x) 15 { 16 int l=Son[x][0],r=Son[x][1]; 17 Size[x]=Size[l]+Size[r]+1; 18 Sum[x]=((long long)Sum[l]*hash[Size[r]+2]%MOD + (long long)Val[x]*hash[Size[r]+1] + Sum[Son[x][1]])%MOD; 19 } 20 21 void Rotate(int x) 22 { 23 int wh=Get(x); 24 int fa=Father[x],fafa=Father[fa]; 25 Father[fa]=x; 26 Son[fa][wh]=Son[x][wh^1]; 27 if (Son[fa][wh]) Father[Son[fa][wh]]=fa; 28 Father[x]=fafa; 29 Son[x][wh^1]=fa; 30 if (fafa) Son[fafa][Son[fafa][1]==fa]=x; 31 Update(fa); 32 Update(x); 33 } 34 35 void Splay(int x,int tar) 36 { 37 for (int fa; (fa=Father[x])!=tar; Rotate(x)) 38 if (Father[fa]!=tar) 39 Rotate(Get(fa)==Get(x)?fa:x); 40 if (!tar) Root=x; 41 } 42 43 int Findx(int x) 44 { 45 int now=Root; 46 while (1) 47 if (Size[Son[now][0]]>=x) 48 now=Son[now][0]; 49 else 50 { 51 x-=Size[Son[now][0]]; 52 if (x==1) 53 { 54 Splay(now,0); 55 return now; 56 } 57 x--; 58 now=Son[now][1]; 59 } 60 } 61 62 void Build(int l,int r,int fa) 63 { 64 if (l>r) return; 65 int mid=(l+r)>>1; 66 Build(l,mid-1,mid); 67 Build(mid+1,r,mid); 68 Father[mid]=fa; 69 Son[fa][mid>fa]=mid; 70 Val[mid]=a[mid]-'a'+1; 71 Update(mid); 72 } 73 74 int Split(int x,int y) 75 { 76 int xx=Findx(x),yy=Findx(y); 77 Splay(xx,0); 78 Splay(yy,xx); 79 return Son[yy][0]; 80 } 81 82 bool check(int len) 83 { 84 int xx=Split(x,x+len+1); 85 int ans1=Sum[xx]; 86 int yy=Split(y,y+len+1); 87 int ans2=Sum[yy]; 88 return ans1==ans2; 89 } 90 91 int main() 92 { 93 hash[1]=1; 94 for (int i=2; i<=200000; ++i) 95 hash[i]=hash[i-1]*27%MOD; 96 97 scanf("%s%d",a+2,&m); 98 n=strlen(a+2); 99 Build(1,n+2,0); 100 Root=(n+3)>>1; 101 sz=n+2; 102 103 104 for (int i=1; i<=m; ++i) 105 { 106 scanf("%s",opt); 107 if (opt[0]=='Q') 108 { 109 scanf("%d%d",&x,&y); 110 int l=1,r=Size[Root]-max(x,y)-1,ans=0; 111 while (l<=r) 112 if (check((l+r)>>1)) 113 { 114 l=((l+r)>>1)+1; 115 ans=l-1; 116 } 117 else 118 r=((l+r)>>1)-1; 119 printf("%d\n",ans); 120 } 121 if (opt[0]=='R') 122 { 123 scanf("%d%s",&p,ch); 124 Findx(p+1); 125 Val[Root]=ch[0]-'a'+1; 126 Update(Root); 127 } 128 if (opt[0]=='I') 129 { 130 scanf("%d%s",&p,ch); 131 Split(p+1,p+2); 132 int x=Son[Root][1]; 133 Val[++sz]=ch[0]-'a'+1; 134 Size[sz]=1; 135 Father[sz]=x; 136 Son[x][0]=sz; 137 Splay(sz,0); 138 } 139 } 140 }