传送门
题解:
由于一个点下方可能有多个不同的转移,原来的均摊分析在这里就失效了,我们可以存一个to数组表示会跳到哪里,这道题字符集很小,直接做就行了。
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;
while(!isdigit(c=gc()));T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int getint(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=1e5+5;
std::vector<int> G[N];
inline void addedge(int u,int v){
G[u].push_back(v);
G[v].push_back(u);
}
char s[N];int tot;
namespace PAM{
int son[N][26],to[N][26],fa[N],len[N],now;
inline void init(){
len[1]=-1,fa[0]=1;now=1;
for(int re i=0;i<26;++i)to[0][i]=1;
}
inline int push_back(char c,int p){
c-='a';
while(s[tot]!=s[tot-len[p]-1])p=to[p][c];
if(!son[p][c]){
len[++now]=len[p]+2;
int k=fa[p];
while(s[tot]!=s[tot-len[k]-1])k=to[k][c];
fa[now]=son[k][c],son[p][c]=now;
memcpy(to[now],to[k],sizeof to[k]);
to[now][s[tot-len[fa[now]]]-'a']=fa[now];
}
return son[p][c];
}
}
ll ans=0;
char c[N];
int id[N],mx[N];
void dfs(int u,int p){
s[++tot]=c[u];
id[u]=PAM::push_back(c[u],id[p]);
mx[u]=std::max(mx[p],PAM::len[id[u]]);
ans+=mx[u];
for(int re v:G[u])if(v!=p)dfs(v,u);
--tot;
}
int n;
signed main(){
// freopen("treepal.in","r",stdin);
PAM::init();
scanf("%d",&n);scanf("%s",c+1);s[0]=-1;
for(int re i=1;i<n;++i)addedge(getint(),getint());
dfs(1,0);
cout<<ans<<"\n";
return 0;
}