[JSOI2008]火星人prefix
1014: [JSOI2008]火星人prefix
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1478 Solved: 399
[Submit][Status][Discuss]
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
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
数据规模:
对于100%的数据,满足:
1、 所有字符串自始至终都只有小写字母构成。
2、 M <= 150,000
3、 字符串长度L自始至终都满足L <= 100,000
4、 询问操作的个数不超过10,000个。
对于第1,2个数据,字符串长度自始至终都不超过1,000
对于第3,4,5个数据,没有插入操作。
1
0
2
1
数据规模:
对于100%的数据,满足:
1、 所有字符串自始至终都只有小写字母构成。
2、 M <= 150,000
3、 字符串长度L自始至终都满足L <= 100,000
4、 询问操作的个数不超过10,000个。
对于第1,2个数据,字符串长度自始至终都不超过1,000
对于第3,4,5个数据,没有插入操作。
Solution:二分答案, SPLAY维护Hash值
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #define maxn 2000001 4 #define L ch[x][0] 5 #define R ch[x][1] 6 using namespace std; 7 struct SplayTree 8 { 9 int sz[maxn], ch[maxn][2], cnt[maxn], pre[maxn], a[maxn], d[maxn], val[maxn], h[maxn], rt, top; 10 char st[maxn]; 11 void up(int x) 12 {//{{{ 13 if (!x) return; 14 sz[x] = sz[L] + sz[R] + 1; 15 if (x != 1 && x != 2) 16 { 17 cnt[x] = cnt[L] + cnt[R] + 1; 18 h[x] = (h[L] + val[x] * d[cnt[L] + 1] + h[R] * d[cnt[L] + 2]); 19 } 20 else 21 { 22 cnt[x] = cnt[L] + cnt[R]; 23 h[x] = h[L] + h[R]; 24 } 25 }//}}} 26 inline void Rotate (int x, int f) 27 {//{{{ 28 int y = pre[x]; 29 ch[y][!f] = ch[x][f]; 30 pre[ ch[x][f] ] = y; 31 pre[x] = pre[y]; 32 if (pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] = x; 33 ch[x][f] = y; 34 pre[y] = x; 35 up (y); 36 }//}}} 37 inline void splay (int x, int goal) 38 {//{{{ 39 while (pre[x] != goal) 40 { 41 if (pre[pre[x]] == goal) Rotate (x ,ch[pre[x]][0] == x); 42 else 43 { 44 int y = pre[x], z = pre[y]; 45 int f = (ch[z][0] == y); 46 if (ch[y][f] == x) Rotate (x, !f), Rotate (x, f); 47 else Rotate (y, f), Rotate (x, f); 48 } 49 } 50 up (x); 51 if (goal == 0) rt = x; 52 }//}}} 53 inline int find(int x, int k) 54 {//{{{ 55 while (1) 56 { 57 if (k < sz[L] + 1) x = L; 58 else 59 if (k > sz[L] + 1) 60 { 61 k -= sz[L] + 1; 62 x = R; 63 } 64 else return x; 65 } 66 }//}}} 67 inline void rep(int x, int dat) 68 {//{{{ 69 int fl = find(rt, x - 1); 70 int fr = find(rt, x + 1); 71 splay(fl, 0), splay(fr, fl); 72 int v = ch[fr][0]; 73 val[v] = dat; 74 up(v); 75 splay(v, 0); 76 }//}}} 77 inline int RHash(int l, int r) 78 {//{{{ 79 int fl = find(rt, l - 1); 80 int fr = find(rt, r + 1); 81 splay(fl, 0), splay(fr, fl); 82 int v = ch[fr][0]; 83 return h[v]; 84 }//}}} 85 inline int GA(int a, int b) 86 {//{{{ 87 int n = sz[rt] - 1; 88 int ans = 0; 89 for (int i = 1 << 18; i; i >>= 1) 90 { 91 if (a + i - 1 <= n && b + i - 1 <= n) 92 { 93 if (RHash(a, a + i - 1) == RHash(b, b + i - 1)) 94 { 95 ans += i; 96 a += i; 97 b += i; 98 } 99 } 100 } 101 return ans; 102 }//}}} 103 void newnode(int &x, int c) 104 {//{{{ 105 val[x = ++top] = c; 106 L = R = 0; 107 sz[x] = cnt[x] = 1; 108 }//}}} 109 void build(int &x, int l, int r, int f) 110 {//{{{ 111 if (l > r) return; 112 int mid = (l + r) / 2; 113 newnode(x, a[mid]); 114 build(L, l, mid - 1, x); 115 build(R, mid + 1, r, x); 116 pre[x] = f; 117 up(x); 118 }//}}} 119 void init() 120 {//{{{ 121 scanf("%s", &st); 122 int n = strlen(st); 123 d[1] = 1; 124 for(int i = 2; i <= 150000; i++) d[i] = d[i - 1] * 27; 125 for(int i = 1; i <= n; i++) a[i] = st[i - 1] - 'a' + 1; 126 top = 2, rt = 1; 127 ch[rt][1] = 2; 128 sz[2] = sz[rt] = pre[2] = 1; 129 int r1; 130 build(r1, 1, n, 2); 131 ch[2][0] = r1; 132 splay(r1, 0); 133 }//}}} 134 inline void insert(int x, int dat) 135 {//{{{ 136 int fl = find(rt, x); 137 int fr = find(rt, x + 1); 138 splay(fl, 0), splay(fr, fl); 139 newnode(ch[fr][0], dat); 140 pre[ ch[fr][0] ] = fr; 141 splay(ch[fr][0], 0); 142 }//}}} 143 inline void getint(int &res) 144 {//{{{ 145 bool flag = true; 146 char chr; 147 res = 0; 148 do 149 chr = getchar(); 150 while ((chr < '0' || chr > '9') && (chr != '-')); 151 if (chr == '-') flag = false, chr = getchar(); 152 do 153 { 154 res = res * 10 + chr - '0'; 155 chr = getchar(); 156 } 157 while (chr >= '0' && chr <= '9'); 158 if (!flag) res = -res; 159 }//}}} 160 inline void printint(int x) 161 {//{{{ 162 if (x < 0) putchar('-'); 163 while (x) 164 { 165 putchar(x % 10 + '0'); 166 x /= 10; 167 } 168 }//}}} 169 void solve() 170 {//{{{ 171 init(); 172 int m, l, r, x; 173 char chr, ch1; 174 getint(m); 175 while(m--) 176 { 177 scanf(" "); 178 scanf("%c", &ch1); 179 switch (ch1) 180 { 181 case 'Q' :getint(l), getint(r), printf("%d\n", GA(l + 1, r + 1)); break; 182 case 'I' :getint(x), scanf(" %c", &chr), insert(x + 1, chr - 'a' + 1); break; 183 case 'R' :getint(x), scanf(" %c", &chr), rep(x + 1, chr - 'a' + 1); break; 184 } 185 } 186 }//}}} 187 }spt; 188 189 int main() 190 { 191 spt.solve(); 192 return 0; 193 }
I come, I see, I conquer!