[JSOI2008]火星人

Description

初始一个串 \(S\),有两种操作。

  1. 在某个位置增/删一个字符。
  2. 询问两个后缀的最长公共前缀。

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);
        }
    }
}
posted @ 2021-08-31 11:09  Kreap  阅读(39)  评论(0编辑  收藏  举报