bzoj 1014[JSOI2008]火星人prefix - 二分 + hash + splay
1014: [JSOI2008]火星人prefix
Time Limit: 10 Sec Memory Limit: 162 MBDescription
火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串: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个数据,没有插入操作。
我们发现要支持修改操作,所以后缀数组就不适用了
查询两个字符串的lcp有两个很常见的算法, 后缀数组和 二分哈希
所以对于字符串的修改我们用一个splay 来维护, 平衡树每个节点表示的是对应子树的字符串的哈希值。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define LL long long 6 using namespace std; 7 8 const int MAXN = 1e5 + 10, MAXM = 2e5 + 10; 9 int N, M; 10 int root; 11 int ans = 0; 12 int tot = 0; 13 char opr[30], d[30]; 14 unsigned long long pow[MAXN]; 15 struct spl { 16 int ch[2]; 17 int fa; 18 unsigned LL c; 19 int size; 20 unsigned LL hash; 21 void init() 22 { 23 ch[0] = ch[1] = 0; 24 size = 0; 25 hash = 0; 26 c = 0; 27 fa = 0; 28 } 29 } t[MAXN * 50]; 30 inline LL read() 31 { 32 LL x = 0, w = 1; char ch = 0; 33 while(ch < '0' || ch > '9') { 34 if(ch == '-') { 35 w = -1; 36 } 37 ch = getchar(); 38 } 39 while(ch >= '0' && ch <= '9') { 40 x = x * 10 + ch - '0'; 41 ch = getchar(); 42 } 43 return x * w; 44 } 45 46 char s[MAXN]; 47 48 void pushup(int k) 49 { 50 t[k].size = t[t[k].ch[0]].size + t[t[k].ch[1]].size + 1; 51 t[k].hash = t[t[k].ch[0]].hash * pow[t[t[k].ch[1]].size + 1] + t[k].c * pow[t[t[k].ch[1]].size] + t[t[k].ch[1]].hash; 52 } 53 54 void rotate(int x, int &k) 55 { 56 int y = t[x].fa, z = t[y].fa; 57 int l = 0, r; 58 if(y == k) { 59 k = x; 60 } 61 if(t[y].ch[0] == x) { 62 l = 0; 63 } else { 64 l = 1; 65 } 66 r = l ^ 1; 67 if(z) { 68 if(t[z].ch[0] == y) { 69 t[z].ch[0] = x; 70 } else { 71 t[z].ch[1] = x; 72 } 73 } 74 int tt = t[x].ch[r]; 75 t[x].ch[r] = y, t[x].fa = z, t[tt].fa = y; 76 t[y].ch[l] = tt, t[y].fa = x; 77 pushup(y), pushup(x); 78 } 79 80 void splay(int x, int &k) 81 { 82 while(x != k) { 83 int y = t[x].fa, z = t[y].fa; 84 if(y != k) { 85 if(t[z].ch[0] == y ^ t[y].ch[0] == x) { 86 rotate(x, k); 87 } else { 88 rotate(y, k); 89 } 90 } 91 rotate(x, k); 92 } 93 } 94 95 unsigned LL judge(int st, int len) 96 { 97 int k = root; 98 int loc = st; 99 while(loc != t[t[k].ch[0]].size + 1) { 100 if(loc > t[t[k].ch[0]].size) { 101 loc = loc - t[t[k].ch[0]].size - 1; 102 k = t[k].ch[1]; 103 } else { 104 k = t[k].ch[0]; 105 } 106 } 107 splay(k, root); 108 k = root; 109 loc = st + len + 1; 110 while(loc != t[t[k].ch[0]].size + 1) { 111 if(loc > t[t[k].ch[0]].size) { 112 loc = loc - t[t[k].ch[0]].size - 1; 113 k = t[k].ch[1]; 114 } else { 115 k = t[k].ch[0]; 116 } 117 } 118 splay(k, t[root].ch[1]); 119 return t[t[t[root].ch[1]].ch[0]].hash; 120 } 121 122 void query(int x, int y) 123 { 124 int l = 0, r = tot - max(x, y) - 1; 125 while(l <= r) { 126 int mid = (l + r) >> 1; 127 // cout<<mid<<endl; 128 if(judge(x, mid) == judge(y, mid)) { 129 ans = mid; 130 l = mid + 1; 131 } else { 132 r = mid - 1; 133 } 134 } 135 printf("%d\n", ans); 136 } 137 138 void update(int loc, char d) 139 { 140 int k = root; 141 while(loc != t[t[k].ch[0]].size + 1) { 142 if(loc > t[t[k].ch[0]].size) { 143 loc = loc - t[t[k].ch[0]].size - 1; 144 k = t[k].ch[1]; 145 } else { 146 k = t[k].ch[0]; 147 } 148 } 149 t[k].c = d - 'a'; 150 // pushup(k); 151 splay(k, root); 152 } 153 154 void insert(int x, char d) 155 { 156 int k = root; 157 int loc = x; 158 while(loc != t[t[k].ch[0]].size + 1) { 159 if(loc > t[t[k].ch[0]].size) { 160 loc = loc - t[t[k].ch[0]].size - 1; 161 k = t[k].ch[1]; 162 } else { 163 k = t[k].ch[0]; 164 } 165 } 166 splay(k, root); 167 loc = x + 1; 168 k = root; 169 while(loc != t[t[k].ch[0]].size + 1) { 170 if(loc > t[t[k].ch[0]].size) { 171 loc = loc - t[t[k].ch[0]].size - 1; 172 k = t[k].ch[1]; 173 } else { 174 k = t[k].ch[0]; 175 } 176 } 177 splay(k, t[root].ch[1]); 178 t[++tot].init(); 179 t[t[root].ch[1]].ch[0] = tot; 180 t[tot].fa = t[root].ch[1]; 181 t[tot].size = 1; 182 t[tot].hash = t[tot].c = d - 'a'; 183 pushup(t[root].ch[1]); 184 pushup(root); 185 } 186 187 void build(int l, int r, int &k, int last) 188 { 189 // cout<<l<<" "<<r<<endl; 190 if(l > r) { 191 return; 192 } 193 k = ++tot; 194 if(l == r) { 195 t[k].init(); 196 t[k].size = 1; 197 t[k].c = t[k].hash = s[l] - 'a'; 198 t[k].fa = last; 199 return; 200 } 201 int mid = (l + r) >> 1; 202 t[k].init(); 203 t[k].size = 1; 204 t[k].c = s[mid] - 'a'; 205 t[k].fa = last; 206 build(l, mid - 1, t[k].ch[0], k); 207 build(mid + 1, r, t[k].ch[1], k); 208 pushup(k); 209 } 210 211 void init() 212 { 213 pow[0] = 1; 214 for(int i = 1; i <= 1e5; i++) { 215 pow[i] = pow[i - 1] * 27; 216 } 217 } 218 219 void print(int k) 220 { 221 // cout<<t[k].ch[0]<<" "<<t[k].ch[1]<<" "<<char(t[k].c + 'a')<<" "<<t[k].size<<" "<<t[k].hash<<endl; 222 223 if(t[k].ch[0]) { 224 print(t[k].ch[0]); 225 } 226 //cout<<char(t[k].c + 'a'); 227 if(t[k].ch[1]) { 228 print(t[k].ch[1]); 229 } 230 } 231 232 int main() 233 { 234 init(); 235 /* for(int i = 1; i <= 10; i++) { 236 cout<<pow[i]<<" "; 237 } 238 cout<<endl;*/ 239 t[0].init(); 240 scanf("%s", s + 1); 241 N = strlen(s + 1); 242 N++; 243 s[0] = 'A'; 244 s[N] = 'A'; 245 build(0, N, root, 0); 246 // print(root); 247 M = read(); 248 while(M--) { 249 scanf("%s", opr); 250 if(opr[0] == 'Q') { 251 int x = read(), y = read(); 252 query(x, y); 253 } else if(opr[0] == 'R') { 254 int x = read(); 255 scanf("%s", d); 256 update(x + 1, d[0]); 257 } else { 258 int x = read(); 259 scanf("%s", d); 260 insert(x + 1, d[0]); 261 } 262 } 263 return 0; 264 } 265 266 /* 267 madamimadam 268 7 269 Q 1 7 270 Q 4 8 271 Q 10 11 272 R 3 a 273 Q 1 7 274 I 10 a 275 Q 2 11 276 */