[bzoj1014](JSOI2008)火星人 prefix (Splay维护哈希)
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、 询问。语法:Q x y,x, y均为正整数。功能:计算LCQ(x, y) 限制:1 <= x, y <= 当前字符串长度。 2、 修改。语法:R x d,x是正整数,d是字符。功能:将字符串中第x个数修改为字符d。限制:x不超过当前字符串长度。 3、 插入:语法:I x d,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
数据规模:
对于100%的数据,满足:
1、 所有字符串自始至终都只有小写字母构成。
2、 M <= 150,000
3、 字符串长度L自始至终都满足L <= 100,000
4、 询问操作的个数不超过10,000个。
对于第1,2个数据,字符串长度自始至终都不超过1,000
对于第3,4,5个数据,没有插入操作。
分析
读着前几行,我一直以为这是道后缀数据结构的模板题,结果地球人却整天想着给我出个大难题,把我批判一番
由于插入操作在尾部,而查询固定在了两个后缀的首位,我们没有办法利用后缀数据结构同时满足高效插入和高效查询。这时我们可以考虑更易于动态维护的最长公共前缀查询方法——字符串哈希。一个哈希值就相当于一个多项式,我们可以用一个splay tree维护整个序列,其中每个子树的根节点维护子树对应的子串的哈希值。合并的时候,我们只需计算$(leftchild.h * x + value)*x^{rightchild.size} + rightchild.h$作为根节点的信息就可以了。查询的时候,我们可以二分答案,每次在splay树上查询两段的哈希值是否相等。当然,我们知道字符串哈希都有一定的错误概率,保险起见我们可以用不同的素数作为x的取值维护多个哈希值→_→当然如果用的是自然溢出的话这样可能都是白搭……只要拿来个大素数当模数,世界就会更美好= =
2 Problem: 1014
3 User: AsmDef
4 Language: C++
5 Result: Accepted
6 Time:8932 ms
7 Memory:7664 kb
8 ****************************************************************/
9
10 #include <cctype>
11 #include <cstdio>
12 #include <cmath>
13 #include <iostream>
14 #include <ctime>
15 #include <cstdlib>
16 using namespace std;
17 template<typename T>inline void getd(T &x){
18 char c = getchar();
19 bool minus = 0;
20 while(!isdigit(c) && c != '-')c = getchar();
21 if(c == '-')minus = 1, c = getchar();
22 x = c - '0';
23 while(isdigit(c = getchar()))x = x * 10 - '0' + c;
24 if(minus)x = -x;
25 }
26 /*========================================================*/
27 typedef unsigned long long ull;
28 const int maxn = 100005;
29 const ull p1 = 3127, p2 = 49999, p3 = 2147483647;
30 char tmp[maxn];
31 ull pow1[maxn], pow2[maxn], pow3[maxn];
32 int M;
33 struct Splay{
34 int size, val;
35 ull h1, h2, h3;
36 Splay* init(int);
37 Splay *son[2];
38 int cmp(int k){
39 if(k <= son[0]->size)return 0;
40 if(k - son[0]->size == 1)return -1;
41 return 1;
42 }
43 void update(){
44 size = son[0]->size + son[1]->size + 1;
45 h1 = son[0]->h1 + pow1[son[0]->size]*(p1 * son[1]->h1 + val);
46 h2 = son[0]->h2 + pow2[son[0]->size]*(p2 * son[1]->h2 + val);
47 h3 = son[0]->h3 + pow3[son[0]->size]*(p3 * son[1]->h3 + val);
48 }
49 }Nil, *Root, Pool[maxn];
50 int iter = 0;
51 Splay* Splay::init(int v){
52 val = h1 = h2 = h3 = v;
53 size = 1;
54 son[0] = son[1] = &Nil;
55 return this;
56 }
57 inline void rot(Splay* &o, bool lr){
58 Splay *t = o->son[lr];o->son[lr] = t->son[lr^1];t->son[lr^1] = o;o->update();o = t;o->update();
59 }
60 inline void find(Splay* &o, int k){
61 int c = o->cmp(k);
62 if(c == -1)return;
63 if(c)k -= o->son[0]->size + 1;
64 int c2 = o->son[c]->cmp(k), k2 = k;
65 if(~c2){
66 if(c2)k2 -= o->son[c]->son[0]->size + 1;
67 find(o->son[c]->son[c2], k2);
68 if(c == c2)rot(o, c);
69 else rot(o->son[c], c2);
70 }
71 rot(o, c);
72 }
73 inline Splay *newT(char *str, int len){
74 if(len == 1){return Pool[iter++].init(*str - 'a');}
75 int mid = len >> 1;
76 Splay *t = Pool[iter++].init(str[mid] - 'a');
77 t->son[0] = newT(str, mid);
78 if(len - mid > 1)t->son[1] = newT(str + mid + 1, len - mid - 1);
79 t->update();
80 return t;
81 }
82 inline void init(){
83 Nil.h1 = Nil.h2 = Nil.h3 = Nil.val = Nil.size = 0;
84 int len = 1, i;
85 while(!isalpha(*tmp = getchar()));
86 while(isalpha(tmp[len] = getchar()))++len;
87 getd(M);
88 const int m = min(M + len, maxn - 1);
89 *pow1 = *pow2 = *pow3 = 1;
90 for(i = 1;i <= m;++i)
91 pow1[i] = pow1[i-1]*p1, pow2[i] = pow2[i-1]*p2, pow3[i] = pow3[i-1]*p3;
92 Root = newT(tmp, len);
93 }
94 inline bool check(int x, int y, int len){
95 Splay *t;
96 ull h11, h12, h13, h21, h22, h23;
97 if(x == 1){
98 find(Root, len + 1);
99 t = Root->son[0];
100 }
101 else{
102 find(Root, x - 1);
103 find(Root->son[1], len + 1);
104 t = Root->son[1]->son[0];
105 }
106 h11 = t->h1, h12 = t->h2, h13 = t->h3;
107
108 find(Root, y - 1);
109 if(len == Root->son[1]->size)t = Root->son[1];
110 else{
111 find(Root->son[1], len + 1);
112 t = Root->son[1]->son[0];
113 }
114 h21 = t->h1, h22 = t->h2, h23 = t->h3;
115 if((h11 != h21) || (h12 != h22) || (h13 != h23))return 0;
116 return 1;
117 }
118 inline void Query(){
119 int l = 1, r, x, y, mid;
120 getd(x), getd(y);
121 if(x > y)x ^= y ^= x ^= y;
122 r = Root->size - y + 1;
123 if(x == y){
124 printf("%d", r);
125 if(M)putchar('\n');
126 return;
127 }
128 while(l <= r){
129 mid = (l + r) >> 1;
130 if(check(x, y, mid))l = mid + 1;
131 else r = mid - 1;
132 }
133 printf("%d", r);
134 if(M)putchar('\n');
135 }
136 inline void Change(){
137 int x, d;
138 getd(x);while(!isalpha(d = getchar()));d -= 'a';
139 find(Root, x);
140 Root->val = d;
141 Root->update();
142 }
143 inline void Insert(){
144 int x, d;
145 getd(x);while(!isalpha(d = getchar()));
146 Splay *t = Pool[iter++].init(d - 'a');
147 if(!x){
148 t->son[1] = Root;
149 Root = t;
150 Root->update();
151 return;
152 }
153 find(Root, x);
154 t->son[1] = Root->son[1];Root->son[1] = t;
155 t->update(); Root->update();
156 }
157 int main(){
158 #if defined DEBUG
159 freopen("test", "r", stdin);
160 freopen("out.txt", "w", stdout);
161 #else
162 //freopen("bzoj_1014.in", "r", stdin);
163 //freopen("bzoj_1014.out", "w", stdout);
164 #endif
165 int opt;
166 init();
167 while(M--){
168 while(!isalpha(opt = getchar()));
169 if(opt == 'Q'){
170 Query();
171 }
172 else if(opt == 'R')Change();
173 else Insert();
174 }
175 #if defined DEBUG
176 //cout << endl<< (double)clock() / CLOCKS_PER_SEC << " sec" << endl;
177 #endif
178 return 0;
179 }
180
2 Problem: 1014
3 User: AsmDef
4 Language: C++
5 Result: Accepted
6 Time:4528 ms
7 Memory:4520 kb
8 ****************************************************************/
9
10 #include <cctype>
11 #include <cstdio>
12 #include <iostream>
13 #include <ctime>
14 #include <cstdlib>
15 using namespace std;
16 template<typename T>inline void getd(T &x){
17 char c = getchar();
18 bool minus = 0;
19 while(!isdigit(c) && c != '-')c = getchar();
20 if(c == '-')minus = 1, c = getchar();
21 x = c - '0';
22 while(isdigit(c = getchar()))x = x * 10 - '0' + c;
23 if(minus)x = -x;
24 }
25 /*========================================================*/
26 typedef unsigned long long ull;
27 const int maxn = 100005;
28 const ull p3 = 3127, p1 = 49999, p2 = 2147483647;
29 char tmp[maxn];
30 ull pow1[maxn];
31 int M;
32 struct Splay{
33 int size, val;
34 ull h1;
35 Splay* init(int);
36 Splay *son[2];
37 int cmp(int k){
38 if(k <= son[0]->size)return 0;
39 if(k - son[0]->size == 1)return -1;
40 return 1;
41 }
42 void update(){
43 size = son[0]->size + son[1]->size + 1;
44 h1 = son[0]->h1 + pow1[son[0]->size]*(p1 * son[1]->h1 + val);
45 }
46 }Nil, *Root, Pool[maxn];
47 int iter = 0;
48 Splay* Splay::init(int v){
49 val = h1 = v;
50 size = 1;
51 son[0] = son[1] = &Nil;
52 return this;
53 }
54 inline void rot(Splay* &o, bool lr){
55 Splay *t = o->son[lr];o->son[lr] = t->son[lr^1];t->son[lr^1] = o;o->update();o = t;o->update();
56 }
57 inline void find(Splay* &o, int k){
58 int c = o->cmp(k);
59 if(c == -1)return;
60 if(c)k -= o->son[0]->size + 1;
61 int c2 = o->son[c]->cmp(k), k2 = k;
62 if(~c2){
63 if(c2)k2 -= o->son[c]->son[0]->size + 1;
64 find(o->son[c]->son[c2], k2);
65 if(c == c2)rot(o, c);
66 else rot(o->son[c], c2);
67 }
68 rot(o, c);
69 }
70 inline Splay *newT(char *str, int len){
71 if(len == 1){return Pool[iter++].init(*str - 'a');}
72 int mid = len >> 1;
73 Splay *t = Pool[iter++].init(str[mid] - 'a');
74 t->son[0] = newT(str, mid);
75 if(len - mid > 1)t->son[1] = newT(str + mid + 1, len - mid - 1);
76 t->update();
77 return t;
78 }
79 inline void init(){
80 Nil.h1 = Nil.val = Nil.size = 0;
81 int len = 1, i;
82 while(!isalpha(*tmp = getchar()));
83 while(isalpha(tmp[len] = getchar()))++len;
84 getd(M);
85 const int m = min(M + len, maxn - 1);
86 *pow1 = 1;
87 for(i = 1;i <= m;++i)
88 pow1[i] = pow1[i-1]*p1;
89 Root = newT(tmp, len);
90 }
91 inline bool check(int x, int y, int len){
92 Splay *t;
93 ull h11, h21;
94 if(x == 1){
95 find(Root, len + 1);
96 t = Root->son[0];
97 }
98 else{
99 find(Root, x - 1);
100 find(Root->son[1], len + 1);
101 t = Root->son[1]->son[0];
102 }
103 h11 = t->h1;
104
105 find(Root, y - 1);
106 if(len == Root->son[1]->size)t = Root->son[1];
107 else{
108 find(Root->son[1], len + 1);
109 t = Root->son[1]->son[0];
110 }
111 h21 = t->h1;
112 if(h11 != h21)return 0;
113 return 1;
114 }
115 inline void Query(){
116 int l = 1, r, x, y, mid;
117 getd(x), getd(y);
118 if(x > y)x ^= y ^= x ^= y;
119 r = Root->size - y + 1;
120 if(x == y){
121 printf("%d", r);
122 if(M)putchar('\n');
123 return;
124 }
125 while(l <= r){
126 mid = (l + r) >> 1;
127 if(check(x, y, mid))l = mid + 1;
128 else r = mid - 1;
129 }
130 printf("%d", r);
131 if(M)putchar('\n');
132 }
133 inline void Change(){
134 int x, d;
135 getd(x);while(!isalpha(d = getchar()));d -= 'a';
136 find(Root, x);
137 Root->val = d;
138 Root->update();
139 }
140 inline void Insert(){
141 int x, d;
142 getd(x);while(!isalpha(d = getchar()));
143 Splay *t = Pool[iter++].init(d - 'a');
144 if(!x){
145 t->son[1] = Root;
146 Root = t;
147 Root->update();
148 return;
149 }
150 find(Root, x);
151 t->son[1] = Root->son[1];Root->son[1] = t;
152 t->update(); Root->update();
153 }
154 int main(){
155 #if defined DEBUG
156 freopen("test", "r", stdin);
157 freopen("out.txt", "w", stdout);
158 #else
159 //freopen("bzoj_1014.in", "r", stdin);
160 //freopen("bzoj_1014.out", "w", stdout);
161 #endif
162 int opt;
163 init();
164 while(M--){
165 while(!isalpha(opt = getchar()));
166 if(opt == 'Q')
167 Query();
168
169 else if(opt == 'R')Change();
170 else Insert();
171 }
172 #if defined DEBUG
173 cout << endl<< (double)clock() / CLOCKS_PER_SEC << " sec" << endl;
174 #endif
175 return 0;
176 }