第一眼:树上路径,每个点的度数<=20 ? 树分治!
然而并搞不出来。发现题意是叶子数不超过20。。。
如果以每个叶节点为根建trie树,那么每个串都在这些trie的子串中出现过。深搜每个trie,每个点以父亲为last建后缀自动机。
#include <bits/stdc++.h>
using namespace std;
#define N 4100000
#define ll long long
int n,c,tot;
int a[N],head[N],nex[N],to[N],ls[N],du[N];
void add(int x,int y)
{
tot++;
nex[tot]=head[x];head[x]=tot;
to[tot]=y;
}
struct SAM
{
int trs[N][11],fa[N],len[N],cnt,last;
void init(){last=cnt=1;}
void insert(int x)
{
int p=last,np,q,nq;
if(trs[p][x])
{
q=trs[p][x];
if(len[q]==len[p]+1)np=q;
else
{
fa[nq=++cnt]=fa[q];np=nq;
len[nq]=len[p]+1;
memcpy(trs[nq],trs[q],sizeof(trs[q]));
fa[q]=nq;
for(;p&&trs[p][x]==q;p=fa[p])trs[p][x]=nq;
}
}
else
{
np=++cnt;len[np]=len[last]+1;
for(;p&&!trs[p][x];p=fa[p])trs[p][x]=np;
if(!p)fa[np]=1;
else
{
q=trs[p][x];
if(len[q]==len[p]+1)fa[np]=q;
else
{
fa[nq=++cnt]=fa[q];
len[nq]=len[p]+1;
memcpy(trs[nq],trs[q],sizeof(trs[q]));
fa[q]=fa[np]=nq;
for(;p&&trs[p][x]==q;p=fa[p])trs[p][x]=nq;
}
}
}
last=np;
}
void dfs(int x,int y)
{
last=ls[y];
insert(a[x]);ls[x]=last;
for(int i=head[x];i;i=nex[i])
if(to[i]!=y)
dfs(to[i],x);
}
ll cal()
{
ll ret=0;
for(int i=1;i<=cnt;i++)
ret+=len[i]-len[fa[i]];
return ret;
}
}sam;
int main()
{
//freopen("tt.in","r",stdin);
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1,x,y;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);add(y,x);du[x]++;du[y]++;
}
sam.init();ls[0]=1;
for(int i=1;i<=n;i++)
if(du[i]==1)sam.dfs(i,0);
printf("%lld\n",sam.cal());
return 0;
}