【BZOJ4477】[JSOI2015]字符串树(Trie树)
【BZOJ4477】[JSOI2015]字符串树(Trie树)
题面
题解
对于每个点维护其到根节点的所有字符串构成的\(Trie\),显然可持久化一下就很好写了。
然后每次询问就是\(u+v-2lca\),写个树剖维护\(LCA\)就好了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define MAX 100100
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
char ch[MAX][15];
struct Line{int v,next;char *ch;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v,char *s){e[cnt]=(Line){v,h[u],s};h[u]=cnt++;}
int n,Q,tot;
struct Node{int son[26],v;}t[MAX<<4];
void insert(int &x,char *s,int l,int lim)
{
t[++tot]=t[x];t[x=tot].v+=1;if(l>lim)return;
insert(t[x].son[s[l]-'a'],s,l+1,lim);
}
int Query(int x,char *s,int l)
{
for(int i=1;i<=l;++i)x=t[x].son[s[i]-'a'];
return t[x].v;
}
int rt[MAX],fa[MAX];
int size[MAX],hson[MAX],top[MAX],dep[MAX];
void dfs1(int u,int ff)
{
fa[u]=ff;size[u]=1;dep[u]=dep[ff]+1;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff)continue;
insert(rt[v]=rt[u],e[i].ch,1,strlen(e[i].ch+1));
dfs1(v,u);size[u]+=size[v];
if(size[v]>size[hson[u]])hson[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
if(hson[u])dfs2(hson[u],tp);
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=fa[u]&&e[i].v!=hson[u])
dfs2(e[i].v,e[i].v);
}
int LCA(int u,int v)
{
while(top[u]^top[v])(dep[top[u]]<dep[top[v]])?v=fa[top[v]]:u=fa[top[u]];
return dep[u]<dep[v]?u:v;
}
int main()
{
n=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();scanf("%s",ch[i]+1);
Add(u,v,ch[i]);Add(v,u,ch[i]);
}
dfs1(1,0);dfs2(1,1);
Q=read();
while(Q--)
{
int u=read(),v=read();scanf("%s",ch[0]+1);
int l=strlen(ch[0]+1);
int ans=Query(rt[u],ch[0],l)+Query(rt[v],ch[0],l)-2*Query(rt[LCA(u,v)],ch[0],l);
printf("%d\n",ans);
}
return 0;
}