• [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
    ",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);
            }
        }
    }
    
  • 相关阅读:
    Java函数调用
    Java编程工具的介绍
    Java关键字及作用
    Java面向对象
    Java代码内容概述
    Java构造方法
    Java面向对象
    Java数组概述和定义
    JDBC工具类,基于C3P0的数据库连接池,提供获取连接池、获取连接对象、释放资源和封装事务操作的方法
    图片爬虫工具,可以爬取指定网页的图片
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/15209404.html
Copyright © 2020-2023  润新知