1014: [JSOI2008]火星人prefix
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 6181 Solved: 1974
[ 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、询问。语法: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不超过当前字符串长度
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
1、所有字符串自始至终都只有小写字母构成。
2、M<=150,000
3、字符串长度L自始至终都满足L<=100,000
4、询问操作的个数不超过10,000个。
对于第1,2个数据,字符串长度自始至终都不超过1,000
对于第3,4,5个数据,没有插入操作。
题解:
用区间splay去维护字符串数组,那2、3就是基本的插入、修改操作了
询问最长公共前缀就二分+hash来搞,了解hash基本原理的话很容易将其应用在splay上
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<climits>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define N 2000002
using namespace std;
typedef unsigned long long ll;
const ll sed=27;
int n,m,sz,rt;
char ch[N];int a[N];
int tr[N][2],fa[N],size[N];
ll hash[N],pw[N];int v[N];
inline int read()
{
int x=0,f=1;char ch;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void pushup(int k)
{
int l=tr[k][0],r=tr[k][1];
size[k]=size[l]+size[r]+1;
hash[k]=(hash[l]*pw[size[r]+1]+v[k]*pw[size[r]]+hash[r]);
}
inline void rotate(int x,int &k)
{
int y=fa[x],z=fa[y],l,r;
l=tr[y][1]==x;r=l^1;
if(k==y)k=x;
else tr[z][tr[z][1]==y]=x;
fa[y]=x,fa[x]=z,fa[tr[x][r]]=y;
tr[y][l]=tr[x][r],tr[x][r]=y;
pushup(y);pushup(x);
}
inline void splay(int x,int &k)
{
while(x!=k)
{
int y=fa[x],z=fa[y];
if(y!=k)
{
if(tr[y][0]==x^tr[z][0]==y)
rotate(x,k);
else rotate(y,k);
}rotate(x,k);
}
}
inline int find(int k,int rk)
{
if(!k)return 0;
int l=tr[k][0],r=tr[k][1];
if(size[l]+1==rk)return k;
else if(size[l]>=rk)return find(l,rk);
else return find(r,rk-size[l]-1);
}
inline void new_node(int k)
{
size[k]=1;v[k]=a[k-1];
hash[k]=v[k];
}
inline int build(int l,int r)
{
if(l>r)return 0;int mid=(l+r)>>1;
new_node(mid);
tr[mid][0]=build(l,mid-1);fa[tr[mid][0]]=mid;
tr[mid][1]=build(mid+1,r);fa[tr[mid][1]]=mid;
pushup(mid);return mid;
}
inline int check(int x,int y,int len)
{
int lx=x+1,ly=y+1;
int rx=lx+len-1,ry=ly+len-1;
int a=find(rt,lx-1),b=find(rt,rx+1);
splay(a,rt);splay(b,tr[a][1]);
int k=tr[b][0];ll tmp=hash[k];
a=find(rt,ly-1);b=find(rt,ry+1);
splay(a,rt);splay(b,tr[a][1]);
k=tr[b][0];ll txp=hash[k];
if(tmp==txp)return true;
else return false;
}/*
inline ll query(int k,int len)
{
int x=find(rt,k),y=find(rt,k+len+1);
splay(x,rt);splay(y,tr[rt][1]);
return hash[tr[y][0]];
}*/
inline int ask(int x,int y)
{
int siz=size[rt];
int l=1,r=min(siz-x,siz-y)-1,ret=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(x,y,mid))
l=mid+1,ret=mid;
else r=mid-1;
}
return ret;
}
inline void insert(int x,int y)
{
int a=find(rt,x+1),b=find(rt,x+2);
splay(a,rt);splay(b,tr[a][1]);
int &k=tr[b][0];k=++sz;
size[k]=1,fa[k]=b,v[k]=hash[k]=y;
pushup(b);pushup(a);
}
inline void change(int x,int val)
{
int a=find(rt,x+1);
splay(a,rt);v[a]=val;
pushup(a);
}
/*
abcaab
100
Q 1 5
I 0 a
Q 1 5
*/
int main()
{
// freopen("1014.in","r",stdin);
// freopen("1014.out","w",stdout);
scanf("%s",ch+1);m=read();n=strlen(ch+1);pw[0]=1;
for(int i=1;i<100100;i++)pw[i]=pw[i-1]*sed;
// for(int i=1;i<=strlen(ch+1);i++)
for(int i=1;i<=n;i++)
a[i]=ch[i]-'a'+1;
rt=build(1,n+2);sz=size[rt]+1;
char sh[10],cc[10];
for(int i=1;i<=m;i++)
{
scanf("%s",sh);
if(sh[0]=='Q')
{
int x=read(),y=read();
printf("%d\n",ask(x,y));
}
else if(sh[0]=='I')
{
int x=read();
scanf("%s",cc);
insert(x,cc[0]-'a'+1);
}
else
{
int x=read();
scanf("%s",cc);
change(x,cc[0]-'a'+1);
}
}
}