[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

madamimadam
7
Q 1 7
Q 4 8
Q 10 11
R 3 a
Q 1 7
I 10 a
Q 2 11

Sample Output

5
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的取值维护多个哈希值→_→当然如果用的是自然溢出的话这样可能都是白搭……只要拿来个大素数当模数,世界就会更美好= =

 

  1 /**************************************************************
  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 
Splay Tree维护字符串哈希(三哈希,自然溢出)

 

  1 /**************************************************************
  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 }
Splay Tree维护字符串哈希(单哈希+自然溢出)
posted @ 2015-03-27 11:50  Asm.Definer  阅读(166)  评论(0编辑  收藏  举报