首页 > 代码库 > [BZOJ1014][JSOI2008]火星人prefix
[BZOJ1014][JSOI2008]火星人prefix
[BZOJ1014][JSOI2008]火星人prefix
试题描述
火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串: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函数的值。
输入
第一行给出初始的字符串。第二行是一个非负整数M,表示操作的个数。接下来的M行,每行描述一个操作。操
作有3种,如下所示
1、询问。语法:Qxy,x,y均为正整数。功能:计算LCQ(x,y)限制:1<=x,y<=当前字符串长度。
2、修改。语法:Rxd,x是正整数,d是字符。功能:将字符串中第x个数修改为字符d。限制:x不超过当前字
符串长度。
3、插入:语法:Ixd,x是非负整数,d是字符。功能:在字符串第x个字符之后插入字符d,如果x=0,则在字
符串开头插入。限制:x不超过当前字符串长度
输出
输入示例
madamimadam 7 Q 1 7 Q 4 8 Q 10 11 R 3 a Q 1 7 I 10 a Q 2 11
输出示例
5 1 0 2 1
数据规模及约定
1、所有字符串自始至终都只有小写字母构成。
2、M<=150,000
3、字符串长度L自始至终都满足L<=100,000
4、询问操作的个数不超过10,000个。
对于第1,2个数据,字符串长度自始至终都不超过1,000
对于第3,4,5个数据,没有插入操作。
题解
用 splay 维护 hash 值,查询时二分一下。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); } return x * f; } #define maxn 100010 #define UL unsigned int struct Node { char c; int siz; UL h[2]; Node() {} Node(char _): c(_) {} } ns[maxn]; int ToT, fa[maxn], ch[maxn][2]; char in_S[maxn]; UL idx[maxn][2]; void maintain(int o) { ns[o].siz = 1; for(int i = 0; i < 2; i++) if(ch[o][i]) ns[o].siz += ns[ch[o][i]].siz; int rs = ch[o][1] ? ns[ch[o][1]].siz : 0; for(int i = 0; i < 2; i++) { UL& tmp = ns[o].h[i]; tmp = 0; if(ch[o][1]) tmp += ns[ch[o][1]].h[i]; tmp += idx[rs][i] * (UL)ns[o].c; if(ch[o][0]) tmp += idx[rs+1][i] * ns[ch[o][0]].h[i]; } return ; } void build(int& o, int l, int r) { if(l > r) return ; int mid = l + r >> 1; ns[o = mid] = Node(in_S[mid]); build(ch[o][0], l, mid - 1); build(ch[o][1], mid + 1, r); if(ch[o][0]) fa[ch[o][0]] = o; if(ch[o][1]) fa[ch[o][1]] = o; return maintain(o); } void rotate(int u) { int y = fa[u], z = fa[y], l = 0, r = 1; if(z) ch[z][ch[z][1]==y] = u; if(ch[y][1] == u) swap(l, r); fa[u] = z; fa[y] = u; fa[ch[u][r]] = y; ch[y][l] = ch[u][r]; ch[u][r] = y; maintain(y); maintain(u); return ; } void splay(int u) { while(fa[u]) { int y = fa[u], z = fa[y]; if(z) { if(ch[y][0] == u ^ ch[z][0] == y) rotate(u); else rotate(y); } rotate(u); } return ; } int getrt() { int u = 1; while(fa[u]) u = fa[u]; return u; } int Find(int o, int k) { if(!o) return 0; int ls = ch[o][0] ? ns[ch[o][0]].siz : 0; if(k == ls + 1) return o; if(k > ls + 1) return Find(ch[o][1], k - ls - 1); return Find(ch[o][0], k); } int split(int u) { if(!u) { u = Find(getrt(), 1); splay(u); return u; } splay(u); int tmp = ch[u][1]; fa[tmp] = ch[u][1] = 0; return maintain(u), tmp; } int merge(int a, int b) { if(!a) return maintain(b), b; while(ch[a][1]) a = ch[a][1]; splay(a); ch[a][1] = b; fa[b] = a; return maintain(a), a; } void geths(int ql, int qr, UL& h1, UL& h2) { int tt = getrt(), lrt = Find(tt, ql - 1), mrt = Find(tt, qr), rrt; split(lrt); rrt = split(mrt); // printf("geths: %c %c\n", lrt ? ns[lrt].c : ‘-‘, ns[mrt].c); h1 = ns[mrt].h[0]; h2 = ns[mrt].h[1]; mrt = merge(lrt, mrt); merge(mrt, rrt); return ; } void insert(int p, char c) { int lrt = Find(getrt(), p), mrt, rrt = split(lrt); ns[mrt = ++ToT] = Node(c); maintain(mrt); mrt = merge(lrt, mrt); merge(mrt, rrt); return ; } int main() { idx[0][0] = idx[0][1] = 1; for(int i = 1; i < maxn; i++) idx[i][0] = idx[i-1][0] * 233, idx[i][1] = idx[i-1][1] * 666; scanf("%s", in_S + 1); ToT = strlen(in_S + 1); int rt = 0; build(rt, 1, ToT); int q = read(); while(q--) { char tp[2]; scanf("%s", tp); if(tp[0] == ‘Q‘) { int x = read(), y = read(), l = 0, r = ToT - max(x, y) + 2; while(r - l > 1) { int mid = l + r >> 1; UL h11, h12, h21, h22; geths(x, x + mid - 1, h11, h12); geths(y, y + mid - 1, h21, h22); // printf("%d %u %u %u %u\n", mid, h11, h21, h12, h22); if(h11 == h21 && h12 == h22) l = mid; else r = mid; } printf("%d\n", l); } if(tp[0] == ‘R‘) { int x = Find(getrt(), read()); char tmp[2]; scanf("%s", tmp); ns[x].c = tmp[0]; while(fa[x]) maintain(x), x = fa[x]; maintain(x); } if(tp[0] == ‘I‘) { int x = read(); char tmp[2]; scanf("%s", tmp); insert(x, tmp[0]); } } return 0; }
[BZOJ1014][JSOI2008]火星人prefix