一道好题。
考虑拆分询问,对于经过LCA的出现位置,可以把前链和后链接近LCA部分的slen-1个字符直接取出进行KMP计算,复杂度O(sigema S)
那么现在就要计算树上一条上至下的链形成的串中,询问串出现了多少次(前链是下至上的,把询问串反过来即可)
考虑把这样的询问拆分成两条根到点的链,离线询问,将询问串建成AC自动机。
最后遍历整棵树同时AC自动机识别,搜到对应位置+1,回溯-1,保证记录的是根到链这个串被AC机识别的情况
当树上遍历到询问结束点,AC机上对应询问串结束点fail树的权值和即为答案,用树状数组维护即可
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<vector> using namespace std; const int _=1e2; const int maxn=1e5+_; const int maxs=3e5+_; namespace T { struct node { int x,y,c,next; }a[2*maxn];int len,last[maxn]; void ins(int x,int y,int c) { len++; a[len].x=x;a[len].y=y;a[len].c=c; a[len].next=last[x];last[x]=len; } int f[30][maxn],dep[maxn]; int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=25;i>=0;i--) if(dep[x]-dep[y]>=(1<<i))x=f[i][x]; if(x==y)return x; for(int i=25;i>=0;i--) if(dep[x]>=(1<<i)&&f[i][x]!=f[i][y])x=f[i][x],y=f[i][y]; return f[0][x]; } int findkfa(int x,int k) { for(int i=25;i>=0;i--) if(k>=(1<<i))x=f[i][x],k-=(1<<i); return x; } int c[maxn]; void dfs(int x) { for(int i=1;(1<<i)<=dep[x];i++)f[i][x]=f[i-1][f[i-1][x]]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=f[0][x]) { f[0][y]=x; dep[y]=dep[x]+1; c[y]=a[k].c; dfs(y); } } } vector<int>vec[maxn];int pos[2*maxn]; void hang(int x,int z,int slen,int id) { if(dep[x]-dep[z]<slen)return ; int tx=findkfa(x,dep[x]-dep[z]-(slen-1)); vec[tx].push_back(-id); vec[x].push_back(id); } }using namespace T; char ss[maxs];int slen,as[maxn]; namespace S1 { int sa[2*maxn],alen,p[2*maxn]; int main(int x,int y,int z) { if(dep[x]+dep[y]-2*dep[z]<slen)return 0; alen=0; int tx=findkfa(x,max(0,dep[x]-dep[z]-(slen-1))); while(tx!=z)sa[++alen]=c[tx],tx=f[0][tx]; int tip=alen; int ty=findkfa(y,max(0,dep[y]-dep[z]-(slen-1))); while(ty!=z)sa[++alen]=c[ty],ty=f[0][ty]; reverse(sa+tip+1,sa+alen+1); p[1]=0; int j=0; for(int i=2;i<=slen;i++) { while(j!=0&&ss[i]!=ss[j+1])j=p[j]; if(ss[i]==ss[j+1])j++; p[i]=j; } j=0; int ret=0; for(int i=1;i<=alen;i++) { while(j!=0&&sa[i]!=ss[j+1]-'a'+1)j=p[j]; if(sa[i]==ss[j+1]-'a'+1)j++; if(j==slen)ret++; } return ret; } } namespace S2 { namespace A { struct node { int w[30],fail; }tr[2*maxs];int trlen; void insert(int id) { int now=0; for(int i=1;i<=slen;i++) { int x=ss[i]-'a'+1; if(tr[now].w[x]==0)tr[now].w[x]=++trlen; now=tr[now].w[x]; } T::pos[id]=now; } int head,tail,list[2*maxs]; void bfs() { head=1,tail=2,list[1]=0; while(head!=tail) { int now=list[head]; head++; for(int x=1;x<=26;x++) { int son=tr[now].w[x]; if(son==0)continue; if(now==0)tr[son].fail=0; else { int pre=tr[now].fail; while(pre!=0&&tr[pre].w[x]==0)pre=tr[pre].fail; tr[son].fail=tr[pre].w[x]; } list[tail++]=son; } } } }using namespace A; namespace F { struct node { int x,y,next; }a[4*maxs];int len,last[2*maxs]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int z,L[2*maxs],R[2*maxs]; void dfs(int x) { L[x]=++z; for(int k=last[x];k;k=a[k].next) dfs(a[k].y); R[x]=z; } int s[2*maxs]; int lowbit(int x){return x&-x;} void change(int x,int k){while(x<=trlen+10)s[x]+=k,x+=lowbit(x);} int getsum(int x){int ret=0;while(x>0)ret+=s[x],x-=lowbit(x);return ret;} void update(int x) { for(int i=0;i<T::vec[x].size();i++) { int p=vec[x][i],op=1; if(p<0)op=-1,p=-p; as[p/2]+=op*(getsum(R[pos[p]])-getsum(L[pos[p]]-1)); } } } void dfs(int now,int x) { F::change(F::L[now],1); F::update(x); for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=T::f[0][x]) { int tt=now; while(tt!=0&&tr[tt].w[T::c[y]]==0)tt=tr[tt].fail; dfs(tr[tt].w[T::c[y]],y); } } F::change(F::L[now],-1); } void main() { bfs(); for(int i=1;i<=trlen;i++)F::ins(tr[i].fail,i); F::dfs(0); dfs(0,1); } } int main() { int n,Q,x,y; char sc[3]; scanf("%d%d",&n,&Q); for(int i=1;i<n;i++) { scanf("%d%d%s",&x,&y,sc+1); ins(x,y,sc[1]-'a'+1),ins(y,x,sc[1]-'a'+1); } T::dfs(1); for(int i=1;i<=Q;i++) { scanf("%d%d%s",&x,&y,ss+1); slen=strlen(ss+1); int z=T::LCA(x,y); if(y==z)swap(x,y),reverse(ss+1,ss+slen+1); if(x==z) T::hang(y,x,slen,i*2),S2::insert(i*2); else { as[i]+=S1::main(x,y,z); T::hang(y,z,slen,i*2),S2::insert(i*2); reverse(ss+1,ss+slen+1); T::hang(x,z,slen,i*2+1),S2::insert(i*2+1); } } S2::main(); for(int i=1;i<=Q;i++)printf("%d ",as[i]); return 0; }