题意
给一颗根节点为
1
1
1 的树(节点数
n
≤
6
×
1
0
5
n \leq 6 \times 10^5
n≤6×105),点与点之间用一个小写字母连接。
给一个字符串
S
S
S (长度
l
e
n
≤
8
×
1
0
6
len \leq 8 \times 10^6
len≤8×106 ),称
S
[
l
…
r
]
S[l \dots r]
S[l…r] 与树上的一条从上往下的路径匹配当且仅当
S
[
l
…
r
]
S[l \dots r]
S[l…r] 等于树上该条路径所形成的字符串,求所有的匹配对数。
题解
显然把该树上的广义 s a m sam sam 建出来。
然后把 S S S 一个一个字符放进去匹配。对于 S [ 1 … i ] S[1 \dots i] S[1…i],求出其在树上的最长匹配长度 l e le le 和匹配节点 k k k,所有匹配长度乘以其出现次数的和就是答案。
具体地,我们维护
f
[
x
]
f[x]
f[x] 表示
s
a
m
sam
sam 上该节点所代表的字符串的出现次数。显然,对于一个长度,乘上它的出现次数就是总数。所以我们还要求出它在后缀树上的祖先的长度乘上出现次数,因为其祖先长度小于
l
e
le
le ,所以最长匹配长度就是
l
e
n
[
x
]
−
l
e
n
[
f
a
[
x
]
]
len[x]-len[fa[x]]
len[x]−len[fa[x]]。
这玩意我们用树上前缀和维护一下即可:令
g
[
x
]
=
∑
(
l
e
n
[
y
]
−
l
e
n
[
f
a
[
y
]
]
)
×
f
[
y
]
g[x] = \sum (len[y]-len[fa[y]]) \times f[y]
g[x]=∑(len[y]−len[fa[y]])×f[y] (
y
y
y 为
x
x
x 在后缀树上的祖先)。
然后对于一组
(
k
,
l
e
)
(k,le)
(k,le) 其答案为
(
l
e
−
l
e
n
[
f
a
[
k
]
]
)
×
f
[
k
]
+
g
[
f
a
[
k
]
]
(le-len[fa[k]]) \times f[k]+g[fa[k]]
(le−len[fa[k]])×f[k]+g[fa[k]]。
把所有 ( k , l e ) (k,le) (k,le) 的答案加起来即可。
题解
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=2e6+10;
const int M=2e7+10;
int n;
struct Trie{
int t[N][3],now,las,pos[N],len[N],fa[N],mx[N],f[N];
vector<int> ch[N][3];
LL s[N];
queue<int> q;
int tot,ver[N],fst[N],nxt[N];
inline void jia(int c,int id){
int k=las;las=++now;len[now]=len[k]+1;pos[id]=las;f[las]=1;
while(k&&!t[k][c])t[k][c]=now,k=fa[k];
if(!k)fa[now]=1;
else{
int q=t[k][c];
if(len[q]==len[k]+1)fa[now]=q;
else{
fa[++now]=fa[q];fa[q]=fa[las]=now;len[now]=len[k]+1;
for(int j=0;j<3;++j)t[now][j]=t[q][j];
while(k&&t[k][c]==q)t[k][c]=now,k=fa[k];
}
}
}
inline void add(int x,int y){ver[++tot]=y;nxt[tot]=fst[x];fst[x]=tot;}
inline void jian(){for(int i=2;i<=now;++i)add(fa[i],i);}
void dfs1(int x){
for(int i=fst[x];i;i=nxt[i]){
int y=ver[i];
dfs1(y);
f[x]+=f[y];
}
}
void dfs2(int x){
s[x]+=1ll*(len[x]-len[fa[x]])*f[x];
for(int i=fst[x];i;i=nxt[i]){
int y=ver[i];
s[y]+=s[x];
dfs2(y);
}
}
inline void build(){
las=now=pos[1]=1;
q.push(1);
while(q.size()){
int x=q.front();q.pop();
for(int i=0;i<3;++i){
if(ch[x][i].size()){
for(int j=0;j<(int)ch[x][i].size();++j){
int k=ch[x][i][j];
// cout<<"Trie "<<x<<" "<<i<<" "<<ch[x][i]<<endl;
las=pos[x];
jia(i,k);
q.push(k);
}
}
}
}
}
}T;
char g[M];
LL ans;
int main(){
scanf("%d",&n);
for(int i=2;i<=n;++i){
int x;char s[2];
scanf("%d",&x);scanf("%s",s);
T.ch[x][s[0]-'a'].push_back(i);
}
T.build();T.jian();T.dfs1(1);T.dfs2(1);
scanf("%s",g);
n=strlen(g);
int k=1,len=0;
for(int i=0;i<n;++i){
int c=g[i]-'a';
while(k!=1&&!T.t[k][c])k=T.fa[k],len=T.len[k];
if(!T.t[k][c])k=1,len=0;
else k=T.t[k][c],len++;
// cout<<"FAQ "<<k<<" "<<len<<" "<<T.f[k]<<endl;
ans=ans+1ll*(len-T.len[T.fa[k]])*T.f[k]+T.s[T.fa[k]];
}
printf("%lld\n",ans);
return 0;
}