注意到叶子节点只有20个,从每个叶子节点开始dfs,在得到的trie树上建后缀自动机
比较神奇的是,我们不用考虑那么多奇怪的问题,每个节点只需要从它trie树上的父亲节点开始建后缀自动机,就是对的
讲道理,我连增量法都没理解透,更何况树上的呢,反正直接建就对了
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 100010
using namespace std;
int head[maxn],to[2*maxn],next[2*maxn],d[maxn],w[maxn];
int fa[2*20*maxn],ch[2*20*maxn][26],mx[2*20*maxn];
int n,m,num,tot=1,c;
long long ans;
void addedge(int x,int y) {num++;to[num]=y;next[num]=head[x];head[x]=num;}
int insert(int p,int x)
{
int np=++tot;
mx[np]=mx[p]+1;
while (p && !ch[p][x]) ch[p][x]=np,p=fa[p];
if (!p) fa[np]=1;
else
{
int q=ch[p][x];
if (mx[q]==mx[p]+1) fa[np]=q;
else
{
int nq=++tot;mx[nq]=mx[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
while (p && ch[p][x]==q) ch[p][x]=nq,p=fa[p];
}
}
return np;
}
void dfs(int x,int fa,int p)
{
int now=insert(p,w[x]);
for (int p=head[x];p;p=next[p])
if (to[p]!=fa) dfs(to[p],x,now);
}
int main()
{
scanf("%d%d",&n,&c);
for (int i=1;i<=n;i++) scanf("%d",&w[i]);
for (int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);addedge(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<=tot;i++) ans+=mx[i]-mx[fa[i]];
printf("%lld\n",ans);
return 0;
}