P3346 [ZJOI2015]诸神眷顾的幻想乡

题目

P3346 [ZJOI2015]诸神眷顾的幻想乡

实际上,广义后缀自动机真的不需要特判重复节点,每次移到根重新建就好了

反正有相同的也只会当作\(parent\)且长度相等并不影响\(parent\)树上的操作,下次节点不重复后又会跳\(fail\)来维护原本的状态

做法

有个隐藏条件,树上每个节点的儿子节点不超过\(20\)

我们需要把所有的路径全扔到自动机上去建

其实可以把每个叶子节点当作根遍历一遍,经过的路径插入,可以简单证明出这样能把所有的串遍历完

My complete code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
typedef long long  LL;
const LL maxn=3000000;
inline LL Read(){
    LL x(0),f(1);char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*f;
}
LL n,c,num;
LL a[maxn],du[maxn],head[maxn];
struct node{
    LL to,next;
}dis[maxn];
inline void Add(LL u,LL v){
    dis[++num]=(node){v,head[u]},head[u]=num,++du[u];
}
struct SAM{
    LL nod;
    LL len[maxn],son[maxn][12],fail[maxn];
    inline void Init(){
        nod=1;
        len[0]=-1;
        for(LL i=0;i<=c;++i) son[0][i]=1;
    }
    inline LL Insert(LL c,LL p){
        LL np=++nod;
        len[np]=len[p]+1;
        while(p&&!son[p][c]){
            son[p][c]=np,
            p=fail[p];
        }
        LL q=son[p][c];
        if(len[q]==len[p]+1)
            fail[np]=q;
        else{
            LL nq=++nod; len[nq]=len[p]+1;
            memcpy(son[nq],son[q],sizeof(son[q]));
            fail[nq]=fail[q];
            fail[q]=fail[np]=nq;
            while(p&&son[p][c]==q){
                son[p][c]=nq;
                p=fail[p];
            }
        }
        return np;
    }
    inline LL Calc(){
        LL ret(0);
        for(LL i=2;i<=nod;++i) ret+=len[i]-len[fail[i]];
        return ret;
    }
}S;
void Dfs(LL u,LL fa,LL p){
    p=S.Insert(a[u],p);
    for(LL i=head[u];i;i=dis[i].next){
        LL v(dis[i].to);
        if(v==fa) continue;
        Dfs(v,u,p);
    }
}
int main(){
    n=Read(),c=Read();
    for(LL i=1;i<=n;++i)
        a[i]=Read();
    for(LL i=1;i<n;++i){
        LL u(Read()),v(Read());
        Add(u,v),Add(v,u);
    }
    S.Init();
    for(LL i=1;i<=n;++i)
        if(du[i]==1)
            Dfs(i,0,1);
    printf("%lld",S.Calc());
    return 0;
}
posted @ 2019-01-24 09:15  y2823774827y  阅读(140)  评论(0编辑  收藏  举报