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 else 186 { 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 }