[JSOI2008]火星人 题解

原题链接:\(luogu\)$\ \ $ \(BZOJ\)$\ \ $ \(LOJ\)
题目大意:有一个可以支持插入和修改的字符串,定义函数 \(\operatorname{LCQ(x,y)}\) 表示从 \(x\) 开始的后缀与从 \(y\) 开始的后缀的最长公共前缀。


声明变量:
\(ls\):左儿子
\(rs\):右儿子
\(val\):平衡树维护变量,此题指字符 -'a'
\(sz\):子树大小
\(rk\):对应堆值
\(hs\):哈希值,后面会讲
\(pq\):哈希对应要乘的数字


考虑既然是求最长公共前缀,当然可以通过二分长度来求,用哈希维护即可。
要支持插入和修改,很显然可以用平衡树的 \(FHQ\ Treap\) 进行区间维护。
在原先 \(FHQ\) 需要维护的五个量的基础上,加入 \(hs\),表示其子树内的 \(hash\) 值。
转移方程即为:\(hs[x]=hs[ls[x]]+val[x]\times pq[sz[ls[x]]]+hs[rs[x]]\times pq[sz[ls[x]]+1]\)
插入修改按 \(FHQ\) 原先操作即可


代码:

#include<bits/stdc++.h>
#define ls(x) pl[x].ls
#define rs(x) pl[x].rs
#define val(x) pl[x].val
#define sz(x) pl[x].sz
#define rk(x) pl[x].rk
#define hs(x) pl[x].hs
#define ull unsigned long long
using namespace std;
struct fhq{
    int ls,rs,val,sz,rk;ull hs;
}pl[100005];
int fhq_fail;
ull q=1145141,pq[250005];
int make_node(int x){
    int a=++fhq_fail;
    pl[a]={0,0,x,1,rand(),x};
    return a;
}struct fhq_treap{
    int rt,x,y,z;fhq_treap(){rt=x=y=z=0;}
    void pushup(int p){
        sz(p)=sz(ls(p))+sz(rs(p))+1;
        hs(p)=hs(ls(p))+val(p)*pq[sz(ls(p))]+hs(rs(p))*pq[sz(ls(p))+1];
    }void split(int p,int a,int &x,int &y){
        if(!p){x=y=0;return;}
        if(sz(ls(p))<a) x=p,split(rs(p),a-sz(ls(p))-1,rs(p),y);
        else y=p,split(ls(p),a,x,ls(p));pushup(p);
    }int merge(int x,int y){
        if(!x||!y) return x+y;
        if(rk(x)<rk(y)){
            rs(x)=merge(rs(x),y);
            pushup(x);return x;
        }ls(y)=merge(x,ls(y));
        pushup(y);return y;
    }void add(int a,int b){
        split(rt,a,x,y);
        rt=merge(merge(x,make_node(b)),y);
    }void change(int a,int b){
        split(rt,a,x,z);split(x,a-1,x,y);
        val(y)=hs(y)=b;rt=merge(merge(x,y),z);
    }ull ghs(int l,int r){
        split(rt,r-1,x,z);split(x,l-1,x,y);
        ull re=hs(y);rt=merge(merge(x,y),z);return re;
    }
}a;int n,m;string s;
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
	srand(19820422);cin>>s>>m;
    n=s.size();pq[0]=1;
    for(int i=1;i<=n+m;i++) pq[i]=pq[i-1]*q;
    for(int i=0;s[i];i++) a.rt=a.merge(a.rt,make_node(s[i]-'a'));
    while(m--){
        char c;int x;cin>>c>>x;
        if(c=='Q'){
            int y;cin>>y;if(x>y) swap(x,y);
            int l=1,r=sz(a.rt)-y+1,ans=0;
            while(l<=r){
                int mid=(l+r)/2;
                if(a.ghs(x,x+mid)==a.ghs(y,y+mid))
                    l=mid+1,ans=mid;else r=mid-1;
            }cout<<ans<<"\n";continue;
        }char d;cin>>d;
        if(c=='R') a.change(x,d-'a');
        else a.add(x,d-'a');
    }return 0;
}//Kaká
posted @ 2024-01-19 09:40  长安一片月_22  阅读(9)  评论(0编辑  收藏  举报