1014: [JSOI2008]火星人prefix
Time Limit: 10 Sec
Memory Limit: 162 MB
Submit: 5055
Solved: 1602
[ Submit][ Status][ Discuss]
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
[ Submit][ Status][ Discuss]
嗯。。。打了好长的代码
插入修改操作用splay的merge和split操作轻松解决。。
然后对于每个splay的结点维护其子树hash值
每次询问二分答案然后将子树拆出来比较hash值即可
一开始hash函数没维护好。。。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1E5 + 10;
typedef unsigned long long UL;
const UL hash = 233;
UL fac[maxn];
char A[maxn];
int len;
class data{
private:
struct Node{
Node *ch[2];
UL h;
char c;
int siz;
}*tot,*root,pool[maxn];
void maintain(Node *&x) {
x->siz = 1;
x->h = x->c;
if (x->ch[1] != NULL) {
x->siz += x->ch[1]->siz;
x->h = (x->h + x->ch[1]->h * hash);
}
if (x->ch[0] != NULL) {
x->siz += x->ch[0]->siz;
x->h = x->h * fac[x->ch[0]->siz] + x->ch[0]->h;
}
}
void rotate(Node *&x,int d) {
Node *y = x->ch[d];
x->ch[d] = y->ch[d^1];
y->ch[d^1] = x;
maintain(x);
x = y;
maintain(x);
}
void Insert(Node *&x,int rank,char c) {
if (x == NULL) {
x = ++tot;
x->siz = 1;
x->h = x->c = c;
return;
}
int s0 = (x->ch[0] == NULL)?0:x->ch[0]->siz;
int d;
if (s0 + 1 >= rank) Insert(x->ch[0],rank,c);
else Insert(x->ch[1],rank-1-s0,c);
}
void splay(Node *&x,int rank) {
int s0 = (x->ch[0] == NULL)?0:x->ch[0]->siz;
if (s0+1 == rank) return;
int d1;
if (s0+1 >= rank) d1 = 0;
else d1 = 1,rank = rank-s0-1;
int s1 = (x->ch[d1]->ch[0] == NULL)?0:x->ch[d1]->ch[0]->siz;
if (s1+1 != rank) {
int d2;
if (s1+1 >= rank) d2 = 0;
else d2 = 1,rank = rank-s1-1;
splay(x->ch[d1]->ch[d2],rank);
if (d1 == d2) rotate(x,d1);
else rotate(x->ch[d1],d2);
}
rotate(x,d1);
}
Node *merge(Node *left,Node *right) {
splay(left,left->siz);
left->ch[1] = right;
maintain(left);
return left;
}
void split(Node *o,int k,Node *&left,Node *&right) {
splay(o,k);
left = o;
right = left->ch[1];
left->ch[1] = NULL;
maintain(left);
}
bool Judge(int L,int a,int b) {
if (a + L - 1 > len) return 0;
if (b + L - 1 > len) return 0;
Node *o,*o1,*left,*right;
split(root,a,left,o);
split(o,L,o1,right);
UL h1 = o1->h;
root = merge(left,merge(o1,right));
split(root,b,left,o);
split(o,L,o1,right);
UL h2 = o1->h;
root = merge(left,merge(o1,right));
return h1 == h2;
}
int solve(int a,int b) {
int L,R;
L = 0; R = 1E5 + 10;
while (R - L > 1) {
int mid = (L+R) >> 1;
if (Judge(mid,a,b)) L = mid;
else R = mid;
}
if (Judge(R,a,b)) return R;
else return L;
}
public:
data(){
tot = pool; root = NULL;
}
void Ins(int pos) {
char c;
if (pos >= 0) c = A[pos];
Insert(root,pos+2,c);
splay(root,pos+2);
}
int sol(int a,int b) {
return solve(a,b);
}
void Modify(int pos,char c) {
splay(root,pos+1);
root->c = c;
maintain(root);
}
void Work(int pos,char c) {
Node *left,*right;
split(root,pos+1,left,right);
left->ch[1] = ++tot;
left->ch[1]->siz = 1;
left->ch[1]->h = left->ch[1]->c = c;
maintain(left);
root = merge(left,right);
}
};
int m;
char getord()
{
char ret = getchar();
while (ret != 'Q' && ret != 'R' && ret != 'I') ret = getchar();
return ret;
}
int main()
{
#ifdef YZY
freopen("yzy.txt","r",stdin);
#endif
fac[0] = 1;
for (int i = 1; i <= 100000; i++) fac[i] = fac[i-1]*hash;
scanf("%s",A);
len = strlen(A);
static data tree;
tree.Ins(-1);
for (int i = 0; i < len; i++)
tree.Ins(i);
cin >> m;
while (m--) {
char ord = getord();
if (ord == 'R') {
int pos; scanf("%d",&pos);
char Mod = getchar();
while (Mod < 'a' || Mod > 'z') Mod = getchar();
tree.Modify(pos,Mod);
}
else if(ord == 'I') {
int pos; scanf("%d",&pos);
char Mod = getchar();
while (Mod < 'a' || Mod > 'z') Mod = getchar();
tree.Work(pos,Mod);
++len;
}
else {
int l,r; scanf("%d%d",&l,&r);
printf("%d\n",tree.sol(l,r));
}
}
return 0;
}