bzoj 3926: [Zjoi2015]诸神眷顾的幻想乡【SAM】

时间:2023-01-25 18:53:58

有一个显然的性质就是每个串一定在某个叶子为根的树中是一条直的链
然后因为SAM里是不会有相同状态的,所以以每个叶子为根dfs一遍,并且动态构造SAM(这里的节点u的last指向父亲),最后统计答案就是dis[i]-dis[fa[i]]的和
我看别的题解都说和trie有关……然而并没用用到(也可能是用到了没意识到?)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=4000005;
int n,m,h[N],cnt,d[N],a[N],fa[N],ch[N][15],dis[N],cur=1,con=1;
long long ans;
struct qwe
{
    int ne,to;
}e[N];
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
void add(int u,int v)
{
    cnt++;
    e[cnt].ne=h[u];
    e[cnt].to=v;
    h[u]=cnt;
}
int ins(int c,int p)
{
    cur=++con,dis[cur]=dis[p]+1;
    for(;p&&!ch[p][c];p=fa[p])
        ch[p][c]=cur;
    if(!p)
        fa[cur]=1;
    else
    {
        int q=ch[p][c];
        if(dis[q]==dis[p]+1)
            fa[cur]=q;
        else
        {
            int nq=++con;
            dis[nq]=dis[p]+1;
            memcpy(ch[nq],ch[q],sizeof(ch[q]));
            fa[nq]=fa[q];
            fa[q]=fa[cur]=nq;
            for(;ch[p][c]==q;p=fa[p])
                ch[p][c]=nq;
        }
    }
    return cur;
}
void dfs(int u,int fa,int la)
{
    int nw=ins(a[u],la);
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].to!=fa)
            dfs(e[i].to,u,nw);
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read();
        add(x,y),add(y,x);
        d[x]++,d[y]++;
    }
    for(int i=1;i<=n;i++)
        if(d[i]==1)
            dfs(i,0,1);
    for(int i=1;i<=con;i++)
        ans+=dis[i]-dis[fa[i]];
    printf("%lld\n",ans);
    return 0;
}