[JSOI2008]火星人
Description
初始一个串 \(S\),有两种操作。
- 在某个位置增/删一个字符。
- 询问两个后缀的最长公共前缀。
Solution
一开始以为是什么高级东西…… SAM 并不能处理在中间插入字符的情况,所以应该直接排除了。观察到“最长”这个东西是有单调性的,所以可以考虑二分,然后就转换成两个子串相不相同。可以用哈希来处理。对于修改的话,用平衡树维护一下区间哈希即可。
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<stdlib.h>
using namespace std;
typedef long long ll;
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
const int Bs=233;
const int Mod=998244353;
const int N=1e5+7;
struct Node{
int ls,rs,sz,key,val;
ll Hs;
}t[N];
ll pw[N];
int rt=0;
char s[N];
inline int New(char c){
static int tot=0;
int p=++tot;
t[p]=(Node){0,0,1,rand(),c,c};
return p;
}
#define lid t[id].ls
#define rid t[id].rs
void update(int id){
t[id].sz=t[lid].sz+t[rid].sz+1;
t[id].Hs=(t[lid].Hs+pw[t[lid].sz]*(t[id].val+t[rid].Hs*Bs%Mod)%Mod)%Mod;
}
int merge(int x,int y){
if(!x||!y) return x+y;
if(t[x].key<t[y].key){
t[x].rs=merge(t[x].rs,y);
return update(x),x;
}else{
t[y].ls=merge(x,t[y].ls);
return update(y),y;
}
}
void split(int id,int k,int &x,int &y){
if(!id) x=y=0;
else{
if(t[lid].sz+1<=k)
x=id,split(rid,k-t[lid].sz-1,rid,y);
else y=id,split(lid,k,x,lid);
update(id);
}
}
int query(int l,int r){
int x,y,z;
split(rt,r,y,z);
split(y,l-1,x,y);
int ret=t[y].Hs;
rt=merge(merge(x,y),z);
return ret;
}
int main(){
srand(114514);
pw[0]=1; for(int i=1;i<N;i++) pw[i]=pw[i-1]*Bs%Mod;
scanf("%s",s+1); int m=strlen(s+1);
for(int i=1;i<=m;i++) rt=merge(rt,New(s[i]));
int Q=read(); char op[3];
while(Q--){
scanf("%s",op);
if(op[0]=='Q'){
int x=read(),y=read();
if(x>y) swap(x,y);
int l=1,r=t[rt].sz-y+1,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(query(x,x+mid-1)==query(y,y+mid-1))
l=mid+1,ans=mid;
else r=mid-1;
}
printf("%d\n",ans);
}else if(op[0]=='R'){
int x=read(); char y[2]; scanf("%s",y);
int a,b,c;
split(rt,x,b,c);
split(b,x-1,a,b);
t[b].val=t[b].Hs=y[0];
rt=merge(merge(a,b),c);
}else{
int x=read(); char y[2]; scanf("%s",y);
int a,b; split(rt,x,a,b);
rt=merge(merge(a,New(y[0])),b);
}
}
}