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个数据,没有插入操作。
splay上做Rabin-Karp(字符串哈希)。本身是个水题,但被我做成了毒瘤题= =调了一个晚自习。。。
前半个小时:主体程序
前1个半小时:发现没有初始化
前2个半小时:LCQ(x,y)的x+len可能超过y(没有考虑)
前3个半小时:x可能大于y。。。
#include<bits/stdc++.h>
using namespace std;
const int e1=31,p1=998244353,e2=131,p2=1e9+7;
const int Maxn=100005;
int f1[Maxn]={1},f2[Maxn]={1};
char s[Maxn];
int n;
struct Splay{
int v[Maxn],h1[Maxn],h2[Maxn];
int p[Maxn],siz[Maxn],ch[Maxn][2];
int cnt,root;
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
inline void newnode(int x,int Fa,char alpha){
p[x]=Fa;
siz[x]=1;
ls(x)=rs(x)=0;
v[x]=h1[x]=h2[x]=alpha-'a';
}
inline void maintain(int x){
h1[x]=(1ll*h1[ls(x)]*f1[siz[rs(x)]+1]%p1+1ll*v[x]*f1[siz[rs(x)]]%p1+h1[rs(x)]%p1)%p1;
h2[x]=(1ll*h2[ls(x)]*f2[siz[rs(x)]+1]%p2+1ll*v[x]*f2[siz[rs(x)]]%p2+h2[rs(x)]%p2)%p2;
siz[x]=siz[ls(x)]+siz[rs(x)]+1;
}
inline void rotate(int x){
int f=p[x],gf=p[f],tp=rs(f)==x,son=ch[x][!tp];
ch[p[son]=f][tp]=son,maintain(f);
ch[p[f]=x][!tp]=f,maintain(x);
ch[p[x]=gf][rs(gf)==f]=x;
}
inline void splay(int x,int goal){
if(x==goal)return ;
for(;p[x]^goal;rotate(x))
if((p[p[x]]^goal)&&((rs(p[p[x]])==p[x])==(rs(p[x])==x)))rotate(p[x]);
if(!goal)root=x;
}
inline void build(int &x,int l,int r,int fr){
if(l>r)return ;
int mid=l+r>>1;
newnode(x=++cnt,fr,s[mid]);
build(ls(x),l,mid-1,x),build(rs(x),mid+1,r,x);
maintain(x);
}
inline int findpos(int k){
for(int x=root;;k>siz[ls(x)]+1?k-=siz[ls(x)]+1,x=rs(x):x=ls(x))
if(k==siz[ls(x)]+1)return x;
}
inline pair<int,int> query(int l,int r){
int pre=findpos(l-1),sub=findpos(r+1);
splay(pre,0),splay(sub,pre);
return make_pair(h1[ls(sub)],h2[ls(sub)]);
}
inline void modify(int pos,char alpha){
int x=findpos(pos),pre=findpos(pos-1),sub=findpos(pos+1);
splay(pre,0),splay(sub,pre);newnode(x,sub,alpha);splay(x,0);
}
inline void insert(int pos,char alpha){//插在pos位置后
int pre=findpos(pos),sub=findpos(pos+1);
splay(pre,0),splay(sub,pre);
newnode(ls(sub)=++cnt,sub,alpha);
maintain(sub);maintain(pre);
}
}splay;
inline void query(){
int x,y;scanf("%d%d",&x,&y);
int l=1,r=min(n-x+1,n-y+1),ans=0;
while(l<=r){
int mid=l+r>>1;
if(splay.query(x+1,x+mid)==splay.query(y+1,y+mid))ans=mid,l=mid+1;
else r=mid-1;
}
cout<<ans<<"\n";
}
inline void modify(){
int x;char c;scanf("%d %c",&x,&c);
splay.modify(x+1,c);
}
inline void insert(){
int x;char c;scanf("%d %c",&x,&c);
splay.insert(x+1,c);++n;
}
int main(){
for(int i=1;i<=1e5;++i)f1[i]=1ll*f1[i-1]*e1%p1;
for(int i=1;i<=1e5;++i)f2[i]=1ll*f2[i-1]*e2%p2;
scanf("%s",s+2);n=strlen(s+2);
s[1]='z';s[strlen(s+1)+1]='z';
splay.build(splay.root,1,strlen(s+1),0);
int m;scanf("%d",&m);
for(int i=1;i<=m;++i){
char c=getchar();while(!isalpha(c))c=getchar();
switch(c){
case 'Q':query();break;
case 'R':modify();break;
case 'I':insert();break;
}
}
return 0;
}