bzoj5084 hashit(广义SAM+set动态维护树链的并)

给出的字符串可以很方便的建成Trie树的若干个字符串的形式。
然后我们对Trie树建出广义SAM
那么每次询问的答案就是目前Trie树上所有点在parent树上的点到根的若干树链的并的点i的mx[i]-mx[par[i]]
我们可以用set+dfs序来动态维护树链的并的长度。
注意到x到根的这条树链的贡献其实就是mx[x]
复杂度 O ( 26 n + n l o g n )
改了一晚上,一脑子浆糊gg

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
char s[N];
int n=0,m=0,tfa[N],son[N][26],rt,par[N<<1],mx[N<<1],c[N<<1][26],pos[N];
vector<int>Son[N<<1];ll ans=0;
int dfn[N<<1],dfnum=0,dep[N<<1],fa[N<<1][20],Log[N<<1];
struct Cmp{
    bool operator()(int x,int y){
        return dfn[x]<dfn[y];
    }
};
set<int,Cmp>st;set<int,Cmp>::iterator it;
inline int extend(int p,int ch){
    if(c[p][ch]){
        int q=c[p][ch];
        if(mx[q]==mx[p]+1) return q;
        int nq=++n;memcpy(c[nq],c[q],sizeof(c[q]));
        par[nq]=par[q];par[q]=nq;mx[nq]=mx[p]+1;
        for(;p&&c[p][ch]==q;p=par[p]) c[p][ch]=nq;return nq;
    }int np=++n;mx[np]=mx[p]+1;
    for(;p&&!c[p][ch];p=par[p]) c[p][ch]=np;
    if(!p){par[np]=rt;return np;}
    int q=c[p][ch];
    if(mx[q]==mx[p]+1){par[np]=q;return np;}
    int nq=++n;mx[nq]=mx[p]+1;par[nq]=par[q];par[q]=par[np]=nq;
    memcpy(c[nq],c[q],sizeof(c[q]));
    for(;p&&c[p][ch]==q;p=par[p]) c[p][ch]=nq;return np;
}
inline void build(int p){
    for(int i=0;i<26;++i)
        if(son[p][i]) pos[son[p][i]]=extend(pos[p],i),build(son[p][i]);
}
inline void dfs(int x){
    for(int i=1;i<=Log[n];++i){
        if(!fa[x][i-1]) break;
        fa[x][i]=fa[fa[x][i-1]][i-1];
    }dfn[x]=++dfnum;
    for(int i=0;i<Son[x].size();++i){
        int y=Son[x][i];dep[y]=dep[x]+1;
        fa[y][0]=x;dfs(y);
    }
}
inline int lca(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    int d=dep[x]-dep[y];
    for(int i=0;i<=Log[d];++i)
        if(d>>i&1) x=fa[x][i];
    if(x==y) return x;
    for(int i=Log[n];i>=0;--i)
        if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
int main(){
//  freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);
    scanf("%s",s+1);int Q=strlen(s+1),p=rt=++m;
    for(int i=1;i<=Q;++i){
        if(s[i]=='-'){p=tfa[p];continue;}
        int &y=son[p][s[i]-'a'];
        if(!y) y=++m;tfa[y]=p;p=y;
    }pos[rt]=++n;build(rt);Log[0]=-1;Log[1]=0;
    for(int i=2;i<=n;++i) Son[par[i]].push_back(i),Log[i]=Log[i>>1]+1;
    dfs(1);p=rt;
    for(int i=1;i<=Q;++i){
        if(s[i]=='-'){
            int x=pos[p];ans-=mx[x];st.erase(x);p=tfa[p];
            it=st.upper_bound(x);
            int succ=0,pre=0;
            if(it!=st.end()) succ=*it;
            if(it!=st.begin()) pre=*(--it);
            if(succ) ans+=mx[lca(succ,x)];
            if(pre) ans+=mx[lca(pre,x)];
            if(succ&&pre) ans-=mx[lca(succ,pre)];
        }else{
            p=son[p][s[i]-'a'];int x=pos[p];
            ans+=mx[x];it=st.upper_bound(x);
            int succ=0,pre=0;
            if(it!=st.end()) succ=*it;
            if(it!=st.begin()) pre=*(--it);
            if(succ) ans-=mx[lca(succ,x)];
            if(pre) ans-=mx[lca(pre,x)];
            if(succ&&pre) ans+=mx[lca(succ,pre)];st.insert(x);
        }printf("%lld\n",ans);
    }return 0;
}

猜你喜欢

转载自blog.csdn.net/icefox_zhx/article/details/80767439