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

题意:

戳这里

分析:

题目相当于让我们求树上有多少本质不同的路径,但是我们发现直接建 \(trie\) 树的话 \(M\) 字型的路径,没有办法表示出来

然后我们发现题目有这么一句话 由于太阳花田的结构比较特殊,只与一个空地相邻的空地数量不超过 20 个

,这句话提醒了我们换个角度思考问题,我们查看题解可以发现,每一个 \(M\) 型的路径必定可以表示为以一个叶子结点为根的 \(trie\) 树上一条一条直的路径,所以直接以叶子为根建出广义 SAM,求出本质不同的子串

代码:

#include<bits/stdc++.h>

using namespace std;

namespace zzc
{
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }

    const int maxn = 2e6+5;
    int n,cnt;
    int c[maxn],head[maxn],deg[maxn];

    struct edge
    {
        int to,nxt;
    }e[maxn<<1];

    void add(int u,int v)
    {
        e[++cnt].to=v;
        e[cnt].nxt=head[u];
        head[u]=cnt;
        deg[v]++;
    }

    struct trie
    {
        int tot;
        int c[maxn],trans[maxn][15],link[maxn];
        trie(){tot=1;}
        int insert(int f,int x)
        {
            if(!trans[f][x]) trans[f][x]=++tot,link[tot]=f,c[tot]=x;
            return trans[f][x];
        }
    }tr;

    struct suffix_automaton
    {
        int tot;
        int trans[maxn][15],link[maxn],id[maxn],len[maxn];
        queue<int> q;
        suffix_automaton(){tot=1;}

        int insert(int x,int lst)
        {
            int cur=++tot,tmp=lst;
            len[cur]=len[tmp]+1;
            for(;tmp&&!trans[tmp][x];tmp=link[tmp]) trans[tmp][x]=cur;
            if(!tmp)
            {
                link[cur]=1;
            }
            else
            {
                int q=trans[tmp][x];
                if(len[tmp]+1==len[q])
                {
                    link[cur]=q;
                }
                else
                {
                    int clone=++tot;
                    len[clone]=len[tmp]+1;
                    for(int i=0;i<=10;i++) trans[clone][i]=trans[q][i];
                    link[clone]=link[q];
                    link[cur]=link[q]=clone;
                    for(;tmp&&trans[tmp][x]==q;tmp=link[tmp]) trans[tmp][x]=clone;
                }
            }
            return cur;
        }
    
        void build()
        {
            for(int i=0;i<=10;i++) if(tr.trans[1][i]) q.push(tr.trans[1][i]);
            id[1]=1;
            while(!q.empty())
            {
                int u=q.front();q.pop();
                id[u]=insert(tr.c[u],id[tr.link[u]]);
                for(int i=0;i<=10;i++) if(tr.trans[u][i]) q.push(tr.trans[u][i]);
            }
        }

        void sort()
        {
            long long ans=0;
            for(int i=2;i<=tot;i++) ans+=len[i]-len[link[i]];
            printf("%lld\n",ans);
        }

    }sam;
    
    void dfs(int u,int fa,int lst)
    {
        int tmp=tr.insert(lst,c[u]);
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(v==fa) continue;
            dfs(v,u,tmp);
        }
    }

    void work()
    {
        int a,b;
        n=read();a=read();
        for(int i=1;i<=n;i++) c[i]=read();
        for(int i=1;i<n;i++)
        {
            a=read();b=read();
            add(a,b);add(b,a);
        }
        for(int i=1;i<=n;i++) if(deg[i]==1) dfs(i,0,1);
        sam.build();
        sam.sort();
    }

}

int main()
{
    zzc::work();
    return 0;
}
posted @ 2020-12-31 15:41  youth518  阅读(41)  评论(0编辑  收藏  举报