首页 > 代码库 > 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
7
Q 1 7
Q 4 8
Q 10 11
R 3 a
Q 1 7
I 10 a
Q 2 11
Sample Output
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 #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 }
BZOJ 1014 火星人prefix