• 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;
    }
    
  • 相关阅读:
    SQL server分离和附加数据库
    sql-server的添加数据库文件(日志数据)以及收缩数据库文件(日志数据)
    sql语句中的join用法(可视化解释)
    SQL语句(floor、ceiling和round以及left和right)
    怎样重新获得别人的信任-知识就是力量(思维导图)
    怎样让孩子爱上学习-知识就是力量(思维导图)
    洛谷-P1036 选数
    洛谷-P1028 数的计算
    洛谷-P1914 小书童——密码
    洛谷-P1598 垂直柱状图
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10312646.html
Copyright © 2020-2023  润新知