4477: [Jsoi2015]字符串树

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 373  Solved: 170
[Submit][Status][Discuss]

Description

萌萌买了一颗字符串树的种子,春天种下去以后夏天就能长出一棵很大的字
符串树。字符串树很奇特,树枝上都密密麻麻写满了字符串,看上去很复杂的样
子。
【问题描述】
字符串树本质上还是一棵树,即N个节点N-1条边的连通无向无环图,节点
从1到N编号。与普通的树不同的是,树上的每条边都对应了一个字符串。萌萌
和JYY在树下玩的时候,萌萌决定考一考JYY。每次萌萌都写出一个字符串S和
两个节点U,V,需要JYY立即回答U和V之间的最短路径(即,之间边数最少的
路径。由于给定的是一棵树,这样的路径是唯一的)上有多少个字符串以为前
缀。
JYY虽然精通编程,但对字符串处理却不在行。所以他请你帮他解决萌萌的难题。

Input

输入第一行包含一个整数N,代表字符串树的节点数量。
接下来N-1行,每行先是两个数U,V,然后是一个字符串S,表示节点和U节
点V之间有一条直接相连的边,这条边上的字符串是S。输入数据保证给出的是一
棵合法的树。
接下来一行包含一个整数Q,表示萌萌的问题数。
接来下Q行,每行先是两个数U,V,然后是一个字符串S,表示萌萌的一个问
题是节点U和节点V之间的最短路径上有多少字符串以S为前缀。
输入中所有字符串只包含a-z的小写字母。
1<=N,Q<=100,000,且输入所有字符串长度不超过10。

Output

输出Q行,每行对应萌萌的一个问题的答案。

Sample Input

4
1 2 ab
2 4 ac
1 3 bc
3
1 4 a
3 4 b
3 2 ab

Sample Output

2
1
1

HINT

Source

By 佚名上传

【题解】复习一下轻重链剖分求lca和可持久化Trie的写法。

要求两个点之间的答案,可以转化为ans(x)+ans(y)-2*ans(lca(x,y))

对树上每个子结点,在它的父亲后面建一棵Trie。

每次查询相当于求根到当前点的前缀和。

/********************************************

	Title		4477.cpp
	Author 		TomatoLoveCoconut
	Time		2018-4-02
	History		Created 2018-4-02
	
	Version		1.0.0
	
	Tags:		可持久化Trie


	while(true) RP++;
	
		 QAQ

*********************************************/


#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define base 311
#define mod 19270817
#define maxlongint 2147483647
#define maxint 32767
#define pi (double)acos(-1.0)
#define eps 1e-9
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define mp make_pair
//SGT
#define MID ((l+r)>>1)
#define lson (o<<1)
#define rson (o<<1|1)
//clear the array
#define cla(a) memset(a,0,sizeof(a))
#define clb(a) memset(a,INF,sizeof(a));
#define clc(a) memset(a,-1,sizeof(a));
#define maxn 100010


using namespace std;


//complex
struct Complex{
    double x,y;
    Complex(double xx=0,double yy=0){x=xx,y=yy;}
};
inline Complex operator + (Complex a,Complex b){return Complex(a.x+b.x,a.y+b.y);}
inline Complex operator - (Complex a,Complex b){return Complex(a.x-b.x,a.y-b.y);}
inline Complex operator * (Complex a,Complex b){return Complex(a.x*b.x-a.y*b.y,a.y*b.x+b.y*a.x);}
//BIT
inline int lowbit(int x){return x&(-x);}




//var
char ss[20];
struct Edge{
	int to,next;
	int len;
	char s[20];
}edges[maxn*2];

int b_cnt=0;
int n;
int fa[maxn],dep[maxn],hson[maxn],top[maxn],son[maxn];
int sz[maxn*10];
int ch[maxn*10][26];
int head[maxn];
int rt[maxn];
inline void addedge(int u,int v,char *s)
{
	edges[++b_cnt].next=head[u];
	edges[b_cnt].to=v;
	int n=strlen(s+1);
	edges[b_cnt].len=n;
	for (int i=1;i<=n;i++)
		edges[b_cnt].s[i]=s[i];
	head[u]=b_cnt;
}
inline int idx(char s)
{
	return s-'a';
}
int tot=0;


inline void build(int now,int last,int I,int len)
{
	sz[now]=sz[last]+1;
	if (len>edges[I].len)
		return ;
	for (int i=0;i<26;i++)
		if (i!=idx(edges[I].s[len]))
			ch[now][i]=ch[last][i];
	ch[now][idx(edges[I].s[len])]=++tot;
	build(tot,ch[last][idx(edges[I].s[len])],I,len+1);
}


inline void dfs_1(int u,int f)
{
	dep[u]=dep[f]+1;
	fa[u]=f;
	son[u]=1;
	for (int i=head[u];i;i=edges[i].next)
	{
		int v=edges[i].to;
		if (v!=f)
		{
			rt[v]=++tot;
			build(rt[v],rt[u],i,1);
			dfs_1(v,u);
			son[u]+=son[v];
			if (!hson[u] || son[v]>son[hson[u]])
				hson[u]=v;
		}
	}
}
inline void dfs_2(int u,int tp)
{
	top[u]=tp;
	if (!hson[u]) return ;
	dfs_2(hson[u],tp);
	for (int i=head[u];i;i=edges[i].next)
	{
		int v=edges[i].to;
		if (v!=fa[u] && v!=hson[u])
			dfs_2(v,v);
	}
}
inline int lca(int x,int y)
{
	for (;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]);
	return dep[x]<dep[y]?x:y;
}
inline int query(int o)
{
	int len=strlen(ss+1);
	for (int i=1;i<=len;i++)
		o=ch[o][idx(ss[i])];
	return sz[o];
}

int main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	scanf("%d",&n);
	int x,y;
	for (int i=1;i<n;i++)
	{
		scanf("%d%d%s",&x,&y,ss+1);
		addedge(x,y,ss);
		addedge(y,x,ss);
	}
	dfs_1(1,0);
	dfs_2(1,1);
	int q;
	scanf("%d",&q);
	for (int i=1;i<=q;i++)
	{
		scanf("%d%d%s",&x,&y,ss+1);
		printf("%d\n",query(rt[x])+query(rt[y])-2*query(rt[lca(x,y)]));
	}
	return 0;
}













/****************************************************
		Any Questions Please Contact Me
		Tencent QQ:	898021802
		Website:	primopan.org
		Email:		primojpan@gmail.com
****************************************************/

 


发表评论

电子邮件地址不会被公开。 必填项已用*标注