BZOJ 3926 Zjoi2015 诸神眷顾的幻想乡 后缀自动机

题目大意:给定一棵树,每个节点有一个字符,求从一个节点出发沿最短路径走到另一个节点所构成的字符串一共有多少种

此生无悔入东方,来世愿生幻想乡

题目戳这里

注意一句话:太阳花田的结构比较特殊,只与一个空地相邻的空地的数量不超过20个

有奖问答:↑你看到这句话的第一反应是啥?

1.度数<=20

2.叶节点数<=20

仔细看几遍就能找到答案~

[捂脸熊]陈老师真是语文高手。。。。

叶节点数<=20还做啥了。。。

直接从每个叶节点DFS一遍,然后构建广义后缀自动机,最终答案就是每个节点的深度-parent节点的深度之和

还有一种后缀数组的做法是DFS20遍构建一棵Trie树,然后将Trie树建成后缀数组(OTZ),然后一样搞就是了

OTZ

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
struct abcd{
    int to,next;
}table[M<<1];
int head[M],tot;
int n,c,a[M];
long long ans;
int degree[M];
void Add(int x,int y)
{
    table[++tot].to=y;
    table[tot].next=head[x];
    head[x]=tot;
}
namespace Suffix_Automaton{
    struct Sam{
        Sam *son[10],*parent;
        int max_dpt;
        bool v;
        void* operator new (size_t,int _)
        {
            #define L (1<<15)
            static Sam *mempool,*C;
            if(C==mempool)
                mempool=(C=new Sam[L])+L;
            C->max_dpt=_;
            C->parent=0x0;
            C->v=false;
            memset(C->son,0,sizeof C->son);
            return C++;
        }
    }*root=new (0)Sam;
    Sam* Extend(Sam *p,int x)
    {
        if(p->son[x]&&p->son[x]->max_dpt==p->max_dpt+1)
            return p->son[x];
        Sam *np=new (p->max_dpt+1)Sam;
        while(p&&!p->son[x])
            p->son[x]=np,p=p->parent;
        if(!p)
            np->parent=root;
        else
        {
            Sam *q=p->son[x];
            if(p->max_dpt+1==q->max_dpt)
                np->parent=q;
            else
            {
                Sam *nq=new (p->max_dpt+1)Sam;
                nq->parent=q->parent;
                memcpy(nq->son,q->son,sizeof nq->son);
                q->parent=nq;np->parent=nq;
                for(;p&&p->son[x]==q;p=p->parent)
                    p->son[x]=nq;
            }
        }
        return np;
    }
}
using namespace Suffix_Automaton;
Sam *node[M];
void DFS(int x,int from)
{
    int i;
    node[x]=Extend(node[from],a[x]);
    for(i=head[x];i;i=table[i].next)
        if(table[i].to!=from)
            DFS(table[i].to,x);
}
void BFS()
{
    static Sam *q[4004004];
    int i,r=0,h=0;
    q[++r]=root;
    while(r!=h)
    {
        Sam *p=q[++h];
        if(p!=root)
            ans+=p->max_dpt-p->parent->max_dpt;
        for(i=0;i<c;i++)
            if(p->son[i]&&!p->son[i]->v)
                p->son[i]->v=true,q[++r]=p->son[i];
    }
}
int main()
{
    int i,x,y;
    cin>>n>>c;
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        Add(x,y);Add(y,x);
        degree[x]++;
        degree[y]++;
    }
    node[0]=root;
    for(i=1;i<=n;i++)
        if(degree[i]==1)
            DFS(i,0);
    BFS();
    cout<<ans<<endl;
    return 0;
}


你可能感兴趣的:(后缀自动机,bzoj,BZOJ3926)