传送门
题解:
一个串在从 u u u到 v v v的路径上匹配,我们直接分情况搞。
首先,匹配没有横跨LCA,那么一定是 L C A − > u LCA->u LCA−>u的路径上匹配反串, L C A − > v LCA->v LCA−>v匹配原串,直接用AC的fail树上DFS序离线上树状数组,一波就能搞了。
然后是横跨了LCA的,直接把前后提一个 ∣ S ∣ − 1 |S|-1 ∣S∣−1长度的串出来做匹配就行了。
代码(用了C++11):
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
cs int Rlen=1<<22|1;
char buf[Rlen],*p1,*p2;
inline char get_char(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
inline char peek(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1;}
inline char ga(){while(!isalpha(peek()))++p1;return *p1++;}
inline int get_s(char *s){
int len=0;char c;
while(isspace(c=gc()));
while(s[len++]=c,!isspace(c=gc())&&c!=EOF);
s[len]='\0';return len;
}
template<typename T>
inline T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
using pii=std::pair<int,int>;
#define fi first
#define se second
cs int N=1e5+7,M=3e5+7;
struct edge{int to,c;};
struct Query{int p,id;};
std::vector<edge> G[N];
std::vector<Query> qry[N];
inline void adde(int u,int v,int w){
G[u].push_back((edge){v,w});
G[v].push_back((edge){u,w});
}
inline void addQ(int u,int v,int w){
qry[u].push_back((Query){v,w});
}
int d[N],fa[N],fs[N];
int siz[N],in[N],nd[N],top[N],son[N],dfn;
void dfs1(int u,int p){
siz[u]=1;
for(auto e:G[u])if(e.to!=p){
fa[e.to]=u;d[e.to]=d[u]+1;fs[e.to]=e.c;
dfs1(e.to,u);siz[u]+=siz[e.to];
if(siz[e.to]>siz[son[u]])son[u]=e.to;
}
}
void dfs2(int u,int tp){
nd[in[u]=++dfn]=u;top[u]=tp;
if(son[u])dfs2(son[u],tp);
for(auto e:G[u])if(e.to!=fa[u]&&e.to!=son[u])dfs2(e.to,e.to);
}
inline int LCA(int u,int v){
while(top[u]!=top[v])d[top[u]]>d[top[v]]?u=fa[top[u]]:v=fa[top[v]];
return d[u]<d[v]?u:v;
}
inline int Kth(int u,int k){
while(d[u]-d[top[u]]<k)k-=d[u]-d[top[u]]+1,u=fa[top[u]];
return nd[in[u]-k];
}
char s[M];int len;
namespace KMP{
int nxt[M],a[N],tp;
inline int solve_cross(int u,int v,int p){
for(int re i=2,j=0;i<=len;++i){
while(j&&s[j+1]!=s[i])j=nxt[j];
if(s[j+1]==s[i])++j;nxt[i]=j;
}tp=0;int re j=0,ans=0;
u=Kth(u,d[u]-std::min(d[p]+len-1,d[u]));
v=Kth(v,d[v]-std::min(d[p]+len-1,d[v]));
for(;u!=p;u=fa[u]){
while(j&&s[j+1]!=fs[u])j=nxt[j];
if(s[j+1]==fs[u])++j;
}
for(;v!=p;v=fa[v])a[++tp]=fs[v];
while(tp){
while(j&&s[j+1]!=a[tp])j=nxt[j];
if(s[j+1]==a[tp])++j;
if(j==len)++ans,j=nxt[j];
--tp;
}
return ans;
}
}
namespace AC{
cs int M=::M<<1;
int cnt;
int son[M][26],fail[M];
std::vector<int> G[M];
int in[M],out[M],dfn;
inline int ins(){
int u=0;
for(int re i=1;i<=len;++i){
int c=s[i];
if(!son[u][c])son[u][c]=++cnt;
u=son[u][c];
}
return u;
}
void dfs_fail(int u){
in[u]=++dfn;
for(int re v:G[u])dfs_fail(v);
out[u]=dfn;
}
inline void build_AC(){
std::queue<int> q;
for(int re i=0;i<26;++i)if(son[0][i])q.push(son[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
for(int re i=0;i<26;++i)
son[u][i]?(q.push(son[u][i]),fail[son[u][i]]=son[fail[u]][i]):(son[u][i]=son[fail[u]][i]);
}
for(int re i=cnt;i;--i)G[fail[i]].push_back(i);
dfs_fail(0);
}
int tr[M];
inline void add(int p,int v){for(p=in[p];p<=dfn;p+=p&-p)tr[p]+=v;}
inline int query(int p){int res=0;for(;p;p^=p&-p)res+=tr[p];return res;}
inline int qy(int u){return query(out[u])-query(in[u]-1);}
}
int ans[M];
void dfs3(int u,int ps){
AC::add(ps,1);
for(auto q:qry[u]){
int t=q.id;
if(t>0)ans[t]+=AC::qy(q.p);
else ans[-t]-=AC::qy(q.p);
}
for(auto e:G[u])if(e.to!=fa[u])
dfs3(e.to,AC::son[ps][e.c]);
AC::add(ps,-1);
}
signed main(){
#ifdef zxyoi
freopen("memory.in","r",stdin);
#endif
int n=gi(),m=gi();
for(int re i=1;i<n;++i){
int u=gi(),v=gi();char c=ga();
adde(u,v,c-'a');
}dfs1(1,0);dfs2(1,1);
for(int re i=1;i<=m;++i){
int u=gi(),v=gi(),p=LCA(u,v);len=get_s(s+1);
for(int re j=1;j<=len;++j)s[j]-='a';
ans[i]=KMP::solve_cross(u,v,p);
if(d[v]-d[p]>=len){
int ps=AC::ins();
addQ(v,ps,i);
addQ(Kth(v,d[v]-d[p]-len+1),ps,-i);
}
if(d[u]-d[p]>=len){
std::reverse(s+1,s+len+1);
int ps=AC::ins();
addQ(u,ps,i);
addQ(Kth(u,d[u]-d[p]-len+1),ps,-i);
}
}
AC::build_AC();dfs3(1,0);
for(int re i=1;i<=m;++i)cout<<ans[i]<<"\n";
return 0;
}