[ZJOI2015]诸神眷顾的幻想乡 广义后缀自动机+DFS+语文题

才知道题目中是只有20个叶子节点的意思QAQ....

这次的广义后缀自动机只是将 last 设为 1, 并重新插入.

相比于正统的写法,比较浪费空间.

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector> 
#define setIO(s) freopen(s".in","r",stdin)
#define maxn 3000000
#define ll long long

using namespace std;

ll ans; 
int head[maxn],to[maxn],nex[maxn],edges,de[maxn]; 
int n,C,val[maxn];
void addedge(int u,int v){
    nex[++edges]=head[u],head[u]=edges,to[edges]=v;     
} 
struct SAM{
    int tot,len[maxn],ch[maxn][11],f[maxn]; 
    void init(){ tot = 1; } 
    int extend(int c,int last){
        int np = ++tot,p = last; len[np] = len[last] + 1, last = tot; 
        while(p && !ch[p][c]) ch[p][c] = np,p = f[p];                        
        if(!p) f[np] = 1;
        else{
            int q = ch[p][c]; 
            if(len[q] == len[p] + 1) f[np] = q;
            else {
                int nq = ++tot;
                len[nq] = len[p] + 1; 
                memcpy(ch[nq],ch[q],sizeof(ch[q])); 
                f[nq] = f[q],f[q] = f[np] = nq;
                while(p && ch[p][c] == q) ch[p][c] = nq,p = f[p];
            }
        }  
        return last; 
    }
    void calc(){
        for(int i=1;i<=tot;++i) ans+=len[i]-len[f[i]]; 
    }
}sam; 
void DFS(int u,int fa,int t){
    t = sam.extend(val[u],t);
    for(int v=head[u];v;v=nex[v]){
        if(to[v]==fa) continue;
        DFS(to[v],u,t);
    }
}
int main(){
    //setIO("input");
    scanf("%d%d",&n,&C);
    for(int i=1;i<=n;++i) scanf("%d",&val[i]); 
    for(int i=1;i<n;++i){
        int a,b;
        scanf("%d%d",&a,&b);
        addedge(a,b),addedge(b,a);      
        ++de[a],++de[b]; 
    }
    sam.init(); 
    for(int i=1;i<=n;++i) if(de[i]==1) DFS(i,0,1); 
    sam.calc(); 
    printf("%lld\n",ans); 
    return 0; 
}

  

posted @ 2019-02-12 16:44  EM-LGH  阅读(163)  评论(0编辑  收藏  举报