BZOJ5084: hashit

BZOJ5084: hashit

https://lydsy.com/JudgeOnline/problem.php?id=5084

分析:

  • \(trie\)建立广义后缀自动机,由于是\(trie\),不会有多余结点(lenx==lenfa)
  • 令后缀自动机结点权值为\(len_x-len _ {fa_x}\)
  • 每次询问时答案就等于所有结点到根的树链的并的权值和。
  • 每次是插入一个点,删除一个点,用\(set\)动态维护即可。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <set>
using namespace std;
typedef long long ll;
#define N 100050
#define db(x) cerr<<#x<<" = "<<x<<endl
char opt[N];
int n;
struct Trie {
    int ch[N][26],cnt,fa[N];
    void init() {cnt=1;}
    void Wk() {
        init();
        int i,p=1;
        for(i=1;i<=n;i++) {
            if(opt[i]=='-') {
                p=fa[p];
            }else {
                int &q=ch[p][opt[i]-'a'];
                if(!q) q=++cnt,fa[q]=p;
                p=q;
            }
        }
    }
}t1;
struct Sam {
    #undef N 
    #define N 200050
    int ch[N][26],fa[N],len[N],cnt,Q[N],Lst[N];
    int ke[N],ro[N],f[20][N],Lg[N],dep[N],w[N];
    ll dis[N];
    int head[N],to[N],nxt[N],tot,dfn[N];
    inline void add(int u,int v) {
        to[++tot]=v; nxt[tot]=head[u]; head[u]=tot;
    }
    void dfs(int x) {
        int i; dfn[x]=++dfn[0];
        for(i=head[x];i;i=nxt[i]) {
            dep[to[i]]=dep[x]+1; 
            w[to[i]]=len[to[i]]-len[x];
            dis[to[i]]=dis[x]+w[to[i]];
            dfs(to[i]);
        }
    }
    void init() {cnt=1;}
    int insert(int x,int lst) {
        int p=lst,np=++cnt,q,nq;
        len[np]=len[p]+1; lst=np;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
        if(!p) fa[np]=1;
        else {
            q=ch[p][x];
            if(len[q]==len[p]+1) fa[np]=q;
            else {
                nq=++cnt; 
                len[nq]=len[p]+1; fa[nq]=fa[q]; memcpy(ch[nq],ch[q],sizeof(ch[q]));
                fa[np]=fa[q]=nq;
                for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }return lst;
    }
    int lca(int x,int y) {
        int i;
        if(dep[x]<dep[y]) swap(x,y);
        for(i=Lg[dep[x]];i>=0;i--) {
            if(dep[f[i][x]]>=dep[y]) x=f[i][x];
        }if(x==y) return x;
        for(i=Lg[dep[x]];i>=0;i--) {
            if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
        }return f[0][x];
    }
    struct A {
        int x,v;
        bool operator < (const A &u) const {return v<u.v;}
    };
    set<A>S;
    set<A>::iterator it;
    ll nowans;
    void fadd(int p) {
        A t=(A){p,dfn[p]};
        nowans+=dis[p];
        it=S.upper_bound(t);
        int x=0,y=0;
        if(it!=S.end()) {
            y=it->x;
        }
        if(it!=S.begin()) {
            it--;
            x=it->x;
        }
        if(x) nowans-=dis[lca(x,p)];
        if(y) nowans-=dis[lca(y,p)];
        if(x&&y) nowans+=dis[lca(x,y)];
        S.insert(t);
    }
    void fdel(int p) {
        A t=(A){p,dfn[p]};
        S.erase(t);
        nowans-=dis[p];
        it=S.upper_bound(t);
        int x=0,y=0;
        if(it!=S.end()) {
            y=it->x;
        }
        if(it!=S.begin()) {
            it--;
            x=it->x;
        }
        if(x) nowans+=dis[lca(x,p)];
        if(y) nowans+=dis[lca(y,p)];
        if(x&&y) nowans-=dis[lca(x,y)];
    }
    void Wk() {
        init();
        int p,i,j;
        int l=0,r=0;
        Q[r++]=1; Lst[1]=1;
        while(l<r) {
            p=Q[l++];
            for(i=0;i<26;i++) if(t1.ch[p][i]) {
                int q=t1.ch[p][i];
                Lst[q]=insert(i,Lst[p]);
                Q[r++]=q;
            }
        }
        Lg[0]=-1;
        for(i=1;i<=cnt;i++) f[0][i]=fa[i],Lg[i]=Lg[i>>1]+1;
        for(i=1;(1<<i)<=cnt;i++) {
            for(j=1;j<=cnt;j++) f[i][j]=f[i-1][f[i-1][j]];
        }
        for(i=2;i<=cnt;i++) add(fa[i],i);
        dfs(1);
        p=1;
        for(i=1;i<=n;i++) {
            if(opt[i]=='-') {
                fdel(Lst[p]);
                p=t1.fa[p];
                printf("%lld\n",nowans);
            }else {
                p=t1.ch[p][opt[i]-'a'];
                fadd(Lst[p]);
                printf("%lld\n",nowans);
            }
        }
    }
}t2;
int main() {
    scanf("%s",opt+1);
    n=strlen(opt+1);
    t1.Wk();
    t2.Wk();
}

猜你喜欢

转载自www.cnblogs.com/suika/p/10205835.html