bzoj 1014[JSOI2008]火星人prefix - 二分 + hash + splay

Posted 大财主

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1014[JSOI2008]火星人prefix - 二分 + hash + splay相关的知识,希望对你有一定的参考价值。

我们发现要支持修改操作,所以后缀数组就不适用了

查询两个字符串的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 */
View Code

 

以上是关于bzoj 1014[JSOI2008]火星人prefix - 二分 + hash + splay的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ1014][JSOI2008]火星人prefix

BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)

[BZOJ1014][JSOI2008]火星人prefix splay+二分+hash

[BZOJ]1014 火星人prefix(JSOI2008)

bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix

BZOJ1014 [JSOI2008]火星人prefix