bzoj1014 [JSOI2008]火星人prefix

1014: [JSOI2008]火星人prefix

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 4028  Solved: 1243

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个数据,没有插入操作。


 

 

Source

 

题意:要求维护一个字符串,并要求三个操作,

1、快速回答 第x位开始的后缀 和 第y位开始的后缀     的共同前缀的长度

2、修改第 x 位字符为另一个字符

3、在第x位字符后面添加一个字符

 

分析:本题较常规,也涉及的知识也比较简单

根据题目的范围以及动态修改,显然像后缀数组等等高大上的无法修改的数据结构可以不用考虑

再细看题目,查询不超过1000,说明查询的复杂度可以稍微高一点

灵光一闪,不就是用splay去维护这个字符串就可以了吗?

三个操作都可以实现,

Splay每个节点维护一个Hash值,表示这个节点和它孩子们包括的那段字符串的Hash值,这样就可以Log(Len)内知道某一段的Hash值了

1、查询,二分最长后缀的长度 L,并用Splay求取a....a+Mid-1和b......b+Mid-1这两段的Hash值比较是否相等

2、3、两操作都是Splay的常见操作,不应该不会,Hash值重新算就好

 

综上所述,本题得解

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <deque>
  6 #include <vector>
  7 #include <queue>
  8 #include <iostream>
  9 #include <algorithm>
 10 #include <map>
 11 #include <set>
 12 #include <ctime>
 13 using namespace std;
 14 typedef long long LL;
 15 typedef double DB;
 16 #define For(i, s, t) for(int i = (s); i <= (t); i++)
 17 #define Ford(i, s, t) for(int i = (s); i >= (t); i--)
 18 #define MIT (2147483647)
 19 #define INF (1000000001)
 20 #define MLL (1000000000000000001LL)
 21 #define sz(x) ((int) (x).size())
 22 #define clr(x, y) memset(x, y, sizeof(x))
 23 #define puf push_front
 24 #define pub push_back
 25 #define pof pop_front
 26 #define pob pop_back
 27 #define ft first
 28 #define sd second
 29 #define mk make_pair
 30 inline void SetIO(string Name) {
 31     string Input = Name+".in",
 32     Output = Name+".out";
 33     freopen(Input.c_str(), "r", stdin),
 34     freopen(Output.c_str(), "w", stdout);
 35 }
 36 
 37 const int N = 100010, Mod = 9875321;
 38 struct Node {
 39     int Fa, Child[2];
 40     int Dat, Sum, Hash;
 41     
 42     Node() {
 43         Fa = 0, clr(Child, 0), Dat = Sum = 0;
 44     }
 45     
 46     #define Fa(x) (Tr[x].Fa)
 47     #define C(x, y) (Tr[x].Child[y])
 48     #define Lch(x) (Tr[x].Child[0])
 49     #define Rch(x) (Tr[x].Child[1])
 50     #define Dat(x) (Tr[x].Dat)
 51     #define Sum(x) (Tr[x].Sum)
 52     #define Hash(x) (Tr[x].Hash)
 53 } Tr[N];
 54 int Tot, Root;
 55 int m, Len;
 56 int Fact[N];
 57 string S;
 58 
 59 inline void Input() {
 60     cin>>S;
 61     scanf("%d", &m);
 62 }
 63 
 64 inline void Updata(int x) {
 65     Sum(x) = 1;
 66     For(i, 0, 1) Sum(x) += Sum(C(x, i));
 67     LL Cnt = Hash(Lch(x))*27+Dat(x);
 68     Cnt = Cnt*Fact[Sum(Rch(x))]+Hash(Rch(x));
 69     Hash(x) = Cnt%Mod;
 70 }
 71 
 72 inline void Rotate(int x, int T) {
 73     int y, z;
 74     y = Fa(x); z = Fa(y);
 75     if(Lch(z) == y) Lch(z) = x;
 76     else if(Rch(z) == y) Rch(z) = x;
 77     Fa(x) = z;
 78     C(y, !T) = C(x, T), Fa(C(x, T)) = y;
 79     C(x, T) = y, Fa(y) = x;
 80     Updata(y);
 81 }
 82 
 83 inline void Splay(int x, int Goal) {
 84     int y, z, T1, T2;
 85     while(Fa(x) != Goal) {
 86         y = Fa(x); z = Fa(y);
 87         T1 = (Lch(y) == x), T2 = (Lch(z) == y);
 88         if(z == Goal) Rotate(x, T1);
 89         else if(T1^T2) {
 90             Rotate(x, T1);
 91             Rotate(x, T2);
 92         } else {
 93             Rotate(y, T2);
 94             Rotate(x, T1);
 95         }
 96     }
 97     Updata(x);
 98     if(!Goal) Root = x;
 99 }
100 
101 inline int Find(int w) {
102     int x = Root;
103     while(w) {
104         if(w <= Sum(Lch(x))) x = Lch(x);
105         else if(w == Sum(Lch(x))+1) break;
106         else {
107             w -= 1+Sum(Lch(x));
108             x = Rch(x);
109         }
110     }
111     
112     Splay(x, 0);
113     return x;
114 }
115 
116 inline void Insert(int w, int x) {
117     int L, R;
118     L = Find(w), R = Find(w+1);
119     Splay(L, 0); Splay(R, L);
120     Lch(R) = ++Tot;
121     Fa(Tot) = R, Dat(Tot) = x;
122     Splay(Tot, 0);
123 }
124 
125 inline int Query(int L, int R) {
126     int x, y;
127     x = Find(L-1), y = Find(R+1);
128     Splay(x, 0); Splay(y, x);
129     return Hash(Lch(y));
130 }
131 
132 inline int Work(int A, int B) {
133     if(A > B) swap(A, B);
134     int Left = 0, Right = Len-B+1, Mid, Ret, Hash1, Hash2;
135     A++, B++;
136     while(Left <= Right) {
137         Mid = (Left+Right)>>1;
138         Hash1 = Query(A, A+Mid-1);
139         Hash2 = Query(B, B+Mid-1);
140         if(Hash1 == Hash2) {
141             Ret = Mid;
142             Left = Mid+1;
143         } else Right = Mid-1;
144     }
145     
146     return Ret;
147 }
148 
149 inline void Change(int w, int x) {
150     int A;
151     A = Find(w);
152     Dat(A) = x;
153     Updata(A);
154 }
155 
156 inline void Solve() {
157     Fact[0] = 1;
158     For(i, 1, N-1) Fact[i] = (Fact[i-1]*27)%Mod;
159     
160     Tot = 2, Root = 1;
161     Rch(1) = 2, Sum(1) = 2;
162     Fa(2) = 1, Sum(2) = 1;
163     
164     Len = S.length();
165     For(i, 0, Len-1) {
166         int x = S[i]-'a'+1;
167         Insert(i+1, x);
168     }
169     
170     while(m--) {
171         char Ch = ' ', x = ' ';
172         while(!(Ch >= 'A' && Ch <= 'Z')) Ch = getchar();
173         int a, b, Ret;
174         
175         if(Ch == 'Q') {
176             scanf("%d%d", &a, &b);
177             Ret = Work(a, b);
178             printf("%d\n", Ret);
179         } else if(Ch == 'I') {
180             scanf("%d", &a);
181             while(!(x >= 'a' && x <= 'z')) x = getchar();
182             b = x-'a'+1;
183             Insert(a+1, b);
184             Len++;
185         } else {
186             scanf("%d", &a);
187             while(!(x >= 'a' && x <= 'z')) x = getchar();
188             b = x-'a'+1;
189             Change(a+1, b);
190         }
191     }
192 }
193 
194 int main() {
195     SetIO("1014");
196     Input();
197     Solve();
198     return 0;
199 }
View Code

 

posted @ 2015-06-24 13:17  yanzx6  阅读(135)  评论(0编辑  收藏  举报