【BZOJ4477】[JSOI2015]字符串树(Trie树)

【BZOJ4477】[JSOI2015]字符串树(Trie树)

题面

BZOJ

题解

对于每个点维护其到根节点的所有字符串构成的\(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;
}
posted @ 2018-09-28 14:31  小蒟蒻yyb  阅读(418)  评论(0编辑  收藏  举报