codeforces 291 E. Tree-String Problem (dfs+kmp)

52 篇文章 1 订阅
16 篇文章 0 订阅

E. Tree-String Problem
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

rooted tree is a non-directed connected graph without any cycles with a distinguished vertex, which is called the tree root. Consider the vertices of a rooted tree, that consists of n vertices, numbered from 1 to n. In this problem the tree root is the vertex number 1.

Let's represent the length of the shortest by the number of edges path in the tree between vertices v and u as d(v, u).

parent of vertex v in the rooted tree with the root in vertex r (v ≠ r) is vertex pv, such that d(r, pv) + 1 = d(r, v) and d(pv, v) = 1. For example, on the picture the parent of vertex v = 5 is vertex p5 = 2.

One day Polycarpus came across a rooted tree, consisting of n vertices. The tree wasn't exactly ordinary: it had strings written on its edges. Polycarpus positioned the tree on the plane so as to make all edges lead from top to bottom if you go from the vertex parent to the vertex (see the picture). For any edge that lead from vertex pv to vertex v (1 < v ≤ n), he knows string sv that is written on it. All strings are written on the edges from top to bottom. For example, on the picture s7="ba". The characters in the strings are numbered starting from 0.

An example of Polycarpus's tree (corresponds to the example from the statement)

Polycarpus defines the position in this tree as a specific letter on a specific string. The position is written as a pair of integers (v, x) that means that the position is the x-th letter of the string sv (1 < v ≤ n0 ≤ x < |sv|), where |sv| is the length of string sv. For example, the highlighted letters are positions (2, 1) and (3, 1).

Let's consider the pair of positions (v, x) and (u, y) in Polycarpus' tree, such that the way from the first position to the second goes down on each step. We will consider that the pair of such positions defines string z. String z consists of all letters on the way from (v, x) to(u, y), written in the order of this path. For example, in the picture the highlighted positions define string "bacaba".

Polycarpus has a string t, he wants to know the number of pairs of positions that define string t. Note that the way from the first position to the second in the pair must go down everywhere. Help him with this challenging tree-string problem!

Input

The first line contains integer n (2 ≤ n ≤ 105) — the number of vertices of Polycarpus's tree. Next n - 1 lines contain the tree edges. The i-th of them contains number pi + 1 and string si + 1 (1 ≤ pi + 1 ≤ npi + 1 ≠ (i + 1)). String si + 1 is non-empty and consists of lowercase English letters. The last line contains string t. String t consists of lowercase English letters, its length is at least 2.

It is guaranteed that the input contains at most 3·105 English letters.

Output

Print a single integer — the required number.

Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cincout streams or the %I64dspecifier.

Examples
input
7
1 ab
5 bacaba
1 abacaba
2 aca
5 ba
2 ba
aba
output
6
input
7
1 ab
5 bacaba
1 abacaba
2 aca
5 ba
2 ba
bacaba
output
4
Note

In the first test case string "aba" is determined by the pairs of positions: (2, 0) and (5, 0); (5, 2) and (6, 1); (5, 2) and (3, 1); (4, 0) and (4, 2); (4, 4) and (4, 6); (3, 3) and (3, 5).

Note that the string is not defined by the pair of positions (7, 1) and (5, 0), as the way between them doesn't always go down.



题解:dfs+kmp

这道题后来新加了数据,不这道为什么找到的程序都纷纷TLE,我也华丽的TLE。

感觉就是对模式串建立kmp,一边dfs一边匹配。。

最后记录了一下每个状态出没出现过,如果出现过直接返回之前记录的匹配位置,否则再重新进行匹配。这样子可以减少很多重复的工作。不过之前都不用这么做,难道我们之前学了假的kmp?

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define N 500003
using namespace std;
int n,m,len,tot,v[N],nxt[N],point[N],t[N],r[N],l[N],sum,dp[300010][30];
char s[N*10],ch[N*10];
void add(int x,int y)
{
	tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
}
void build()
{
	len=strlen(s);
	t[0]=-1;
	for (int i=0;i<len;i++) {
		int j=t[i];
		while (j!=-1&&s[i]!=s[j]) j=t[j];
		t[i+1]=++j;
	}
	//for (int i=0;i<=len;i++) cout<<t[i]<<" ";
	//cout<<endl;
}
int track(int k,char c)
{
	if (dp[k][c-'a']!=-1) return dp[k][c-'a'];
	int j=k;
	while (j!=-1&&s[j]!=c) j=t[j];
	j++;
	return dp[k][c-'a']=j;
}
void dfs(int x,int pre)
{
	for (int i=point[x];i;i=nxt[i]){
		int j=l[v[i]]; int k=pre; 
		while (j<=r[v[i]]) {
			k=track(k,ch[j]);
			if (k==len) sum++,k=t[k]; 
			j++;
		}
		dfs(v[i],k);
	}
}
int main()
{
	freopen("a.in","r",stdin);
	scanf("%d",&n); int cnt=0;
	for (int i=2;i<=n;i++) {
		int x; scanf("%d%s",&x,s+1);
		len=strlen(s+1);
		for (int j=1;j<=len;j++) ch[++cnt]=s[j];
		l[i]=r[i-1]+1; r[i]=cnt;
		add(x,i);
	}
	scanf("%s",s);
	build();
	memset(dp,-1,sizeof(dp));
	dfs(1,0);
	printf("%d\n",sum);
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值