首页 > 代码库 > BZOJ 1014 火星人prefix

BZOJ 1014 火星人prefix

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

 

 r_64大神犇告诉我splay+二分+哈希,因此我就写了一发,复杂度O(nlogn^2)。
代码:
技术分享
  1 #include<cstdio>  2 #include<cstdlib>  3 #include<cstring>  4 #include<iostream>  5 using namespace std;  6   7 #define rhl 37  8 #define maxl 100010  9 #define maxm 150010 10 char s[maxl]; int len; 11 unsigned long long mi[maxl+maxm]; 12  13 struct SPLAY 14 { 15     int ch[maxl+maxm][2],fa[maxl+maxm],size[maxl+maxm],key[maxl+maxm],cnt,root; 16     unsigned long long hash[maxl+maxm]; 17  18     inline void updata(int x) 19     { 20         size[x] = size[ch[x][0]] + size[ch[x][1]] + 1; 21         hash[x] = hash[ch[x][0]] * mi[size[ch[x][1]]+1] + mi[size[ch[x][1]]] * (key[x]) + hash[ch[x][1]]; 22     } 23      24     inline void rotate(int x) 25     { 26         int y = fa[x],z = fa[y],l,r; 27         if (ch[y][0] == x) l = 0; else l = 1; r = l ^ 1; 28         if (z != 0) 29         { 30             if (ch[z][0] == y) ch[z][0] = x; else ch[z][1] = x; 31         } 32         fa[x] = z; fa[y] = x; fa[ch[x][r]] = y; 33         ch[y][l] = ch[x][r]; ch[x][r] = y; 34         updata(y); updata(x); 35         fa[0] = 0; ch[0][0] = ch[0][1] = 0; 36     } 37      38     inline void splay(int x,int aim) 39     { 40         int t = fa[aim]; 41         while (fa[x] != t) 42         { 43             int y = fa[x],z = fa[y]; 44             if (fa[y] != t) 45             { 46                 if ((ch[y][0] == x)^(ch[z][0] == y)) rotate(x); 47                 else rotate(y); 48             } 49             rotate(x); 50         } 51         if (aim == root) root = x; 52     } 53      54     inline int find(int rank,int have,int now) 55     { 56         if (size[ch[now][0]]+have+1==rank) return now; 57         if (size[ch[now][0]]+have+1 > rank) return find(rank,have,ch[now][0]); 58         else return find(rank,have+size[ch[now][0]]+1,ch[now][1]); 59     } 60      61     inline void init(int l,int r,int f) 62     { 63         int p; cnt = 0; root = 1; 64         build(l,r,f); 65         p = find(len,0,root); 66         splay(p,root); 67         fa[++cnt] = p; 68         ch[p][1] = cnt; 69         key[cnt] = 0; 70         size[cnt] = 1; 71         updata(p); 72         p = find(1,0,root); 73         splay(p,root); 74         fa[++cnt] = p; 75         ch[p][0] = cnt; 76         key[cnt] = 0; 77         size[cnt] = 1; 78         updata(p); 79     } 80      81     inline void build(int l,int r,int f) 82     { 83         fa[++cnt] = f; 84         if (l == r) 85         { 86             key[cnt] = s[l-1] - a + 1; 87             hash[cnt] = key[cnt]; 88             size[cnt] = 1; 89             return; 90         } 91         int mid = (l+r)>>1,now = cnt; 92         key[now] = s[mid-1] - a + 1; 93         if (mid > l) 94         { 95             ch[now][0] = cnt + 1; 96             build(l,mid - 1,now); 97         } 98         if (mid  < r) 99         {100             ch[now][1] = cnt+1;101             build(mid+1,r,now);102         }103         updata(now);104     }105 106     inline void change(int a,char b)107     {108         int p = find(a+1,0,root);109         splay(p,root);110         key[p] = b-a+1;111         updata(p);112     }113 114     inline void insert(int a,char b)115     {116         int p = find(a+1,0,root),q = find(a+2,0,root);117         splay(p,root);118         splay(q,ch[p][1]);119         fa[++cnt] = q;120         ch[q][0] = cnt; key[cnt] = b-a+1;121         updata(cnt);122         updata(q);123         updata(p);124     }125 126     inline unsigned long long calc(int a,int b)127     {128         int p = find(a,0,root),q = find(b+2,0,root);129         splay(p,root);130         splay(q,ch[p][1]);131         return hash[ch[q][0]];132     }133 }tree;134 135 inline int ask(int a,int b)136 {137     int l = 1,r = min(len-a+1,len-b+1),mid;138     while (l <= r)139     {140         mid = (l + r) >> 1;141         unsigned long long h1 = tree.calc(a,a+mid-1),h2 = tree.calc(b,b+mid-1);142         if (h1 == h2)143             l = mid+1;144         else r = mid - 1;145     }146     return r;147 }148 149 inline void ready()150 {151     mi[0] = 1;152     for (int i = 1;i < maxl+maxm;++i)153         mi[i] = rhl*mi[i-1];154 }155 156 inline int read()157 {158     int x=0,f=1;char ch=getchar();159     while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}160     while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}161     return x*f;162 }163 164 int main()165 {166     freopen("1014.in","r",stdin);167     freopen("1014.out","w",stdout);168     scanf("%s",s); len = strlen(s);169     ready();170     tree.init(1,len,0);171     int T = read(); char opt;172     while (T--)173     {174         scanf("%c",&opt);175         if (opt == Q)176         {177             int a = read(),b = read();178             printf("%d\n",ask(a,b));179         }180         else if (opt == R)181         {182             int a = read(); char b; scanf("%c\n",&b);183             tree.change(a,b);184         }185         else186         {187             int a = read(); char b; scanf("%c\n",&b);188             tree.insert(a,b); ++len;189         }190     }191     fclose(stdin); fclose(stdout);192     return 0;193 }
View Code

 

BZOJ 1014 火星人prefix