51nod 1513 树上的回文

题意:

1513 树上的回文
3.0 秒 131,072.0 KB 80 分 5级题
罗马种了一棵树,树上有n个点。每个点有一个小写英文字母。1号点是树的根,剩下的n-1个点都有一个父亲。点和父亲之间通过一个边相连。第i个点的父亲是pi,且pi<i。

一个点的深度是从根到当前点的路径上经过的点数。根的深度是1。

U在v的子树中,当且仅当u往根方向走可以到达v。特别的,v也是在v的子树中。

罗马给你m个查询,第i个查询包含两个整数vi,hi。现在收集在vi子树中且深度是hi的结点。判断一下把这些结点重新排列是否能组成一个回文。

样例解释:

一个字符串s是回文,当且仅当他正着读和反着读是一样的。空串也是回文。

第一查询中,点1包含z,可以构成回文。

第二个查询中点5和6包含c,d,这个不能组成回文。

第三个查询中,没有点是深度4的,组成一个空串。

第四个查询中,也是构成了一个空串。

第五个查询中,2,3,4符合查询条件,包含字母a,c,c。可以构成cac。

输入
单组测试数据。
第一行包含两个n, m (1≤n,m≤500000),表示树的结点数目和查询数目。
第二行有n-1个数字 p2,p3,…,pn ,表示每一个点的父亲。(1≤pi<i).
接下来一行有n个小写字母,第i个表示第i个点上面的字母。
接下来m行每一行有一个查询,包含vi, hi (1≤vi,hi≤n),表示点编号和深度。
输出
对于每一个查询,如果能够组成回文,输出Yes,否则输出No。
输入样例
6 5
1 1 1 3 3
zacccd
1 1
3 3
4 1
6 1
1 2
输出样例
Yes
No
Yes
Yes
Yes

思路:

To me:”十分优秀,非常优秀“,中文题面都能读错,怕不是睡着了吧!!!

言归正传,这道题写的过程是什么呢?
(1)刚看到题面的时候觉得应该是个树形dp,而回文串,可能当时没想清楚,只想到了偶数情况(所以想到了栈),恰巧题意也读错了,理所应当的没了。。。一把辛酸泪5555

(2)那么真实的题意是什么?给了一棵树,n个点,现在有m次询问,每次询问给出两个数,vi和hi,求的是以vi为根的子树中,深度为hi(以1为根)的点所对应的字母重新排列,能不能构成一个回文串。

(3)怎么做呢?首先我们要求出这棵树的欧拉序,记录刚访问这个节点和出这个节点的时间。

(4)还要求这棵树的dfs序。对于每一层,记录这一层每个节点的时间

(5)对于每一层,还要记录每一层有哪些字符

void dfs(int u,int h){
   //dfs序!!!
	int len = G[u].size();

	mxh = max(mxh,h);//最深的深度
	
	hi[u] = h;//记录每个点的深度
	E[h].push_back(Pow[(s[u] - 'a')]);//记录dfs序
	
	tmp[u].first = ++cnt;//进去的时间
	
	F[h].push_back(cnt);//记录dfs序
	
	for(int i = 0;i < len;i++){
   
		int v = G[u][i];
		dfs(v,h + 1);
	}
	
	tmp[u].second = ++cnt;//不是出来的时间

}

(6)把26个小写英文字符用二进制表示

void init(){
   //表示二进制数
	Pow[0] = 1;
	for(int i 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值