codeforces 570 D. Tree Requests (dsu on the tree)

D. Tree Requests
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Roman planted a tree consisting of n vertices. Each vertex contains a lowercase English letter. Vertex 1 is the root of the tree, each of the n - 1 remaining vertices has a parent in the tree. Vertex is connected with its parent by an edge. The parent of vertex i is vertex pi, the parent index is always less than the index of the vertex (i.e., pi < i).

The depth of the vertex is the number of nodes on the path from the root to v along the edges. In particular, the depth of the root is equal to 1.

We say that vertex u is in the subtree of vertex v, if we can get from u to v, moving from the vertex to the parent. In particular, vertex v is in its subtree.

Roma gives you m queries, the i-th of which consists of two numbers vihi. Let's consider the vertices in the subtree vi located at depthhi. Determine whether you can use the letters written at these vertices to make a string that is a palindrome. The letters that are written in the vertexes, can be rearranged in any order to make a palindrome, but all letters should be used.

Input

The first line contains two integers nm (1 ≤ n, m ≤ 500 000) — the number of nodes in the tree and queries, respectively.

The following line contains n - 1 integers p2, p3, ..., pn — the parents of vertices from the second to the n-th (1 ≤ pi < i).

The next line contains n lowercase English letters, the i-th of these letters is written on vertex i.

Next m lines describe the queries, the i-th line contains two numbers vihi (1 ≤ vi, hi ≤ n) — the vertex and the depth that appear in thei-th query.

Output

Print m lines. In the i-th line print "Yes" (without the quotes), if in the i-th query you can make a palindrome from the letters written on the vertices, otherwise print "No" (without the quotes).

Examples
input
6 5
1 1 1 3 3
zacccd
1 1
3 3
4 1
6 1
1 2
output
Yes
No
Yes
Yes
Yes
Note

String s is a palindrome if reads the same from left to right and from right to left. In particular, an empty string is a palindrome.

Clarification for the sample test.

In the first query there exists only a vertex 1 satisfying all the conditions, we can form a palindrome "z".

In the second query vertices 5 and 6 satisfy condititions, they contain letters "с" and "d" respectively. It is impossible to form a palindrome of them.

In the third query there exist no vertices at depth 1 and in subtree of 4. We may form an empty palindrome.

In the fourth query there exist no vertices in subtree of 6 at depth 1. We may form an empty palindrome.

In the fifth query there vertices 2, 3 and 4 satisfying all conditions above, they contain letters "a", "c" and "c". We may form a palindrome "cac".



题目大意:判断v的子树中所有深度为h的点能否组成一个回文串,每个点上有一个小写字符。

题解:dsu on the tree

将字符压成二进制位,记录每个深度的点的异或值。判断异或值是不是0或者2^x。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 1000003
using namespace std;
int tot,n,m,cnt,q[N],nxt[N],point[N],v[N],val[N],son[N];
int deep[N],size[N],mp[N],c[N],mark[N],ans[N],num[N];
int head[N],u[N],next[N],id[N];
char s[N];
void add(int x,int y)
{
	tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
	tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void build(int x,int y,int i)
{
	tot++; next[tot]=head[x]; head[x]=tot; u[tot]=y; id[tot]=i;
}
void solve(int x,int fa)
{
	deep[x]=deep[fa]+1; size[x]=1;
	for (int i=point[x];i;i=nxt[i]){
		if (v[i]==fa) continue;
		solve(v[i],x);
		size[x]+=size[v[i]];
		if(size[son[x]]<size[v[i]]) son[x]=v[i];
	}
}
void change(int x,int fa,int vl)
{
	mp[deep[x]]^=val[x]; num[deep[x]]+=vl;
	for (int i=point[x];i;i=nxt[i])
	 if (!mark[v[i]]&&v[i]!=fa) change(v[i],x,vl);
}
void dfs(int x,int fa,bool k)
{
	for (int i=point[x];i;i=nxt[i])
	 if (v[i]!=fa&&v[i]!=son[x]) dfs(v[i],x,0);
	if (son[x]) dfs(son[x],x,1),mark[son[x]]=1;
	change(x,fa,1);
	for (int i=head[x];i;i=next[i])
    {
		int t=mp[u[i]];
		if (t==0) ans[id[i]]=1;
		for (int j=0;j<26;j++) 
		 if (!(t^(1<<j))) ans[id[i]]=1;
	}
	if(son[x]) mark[son[x]]=0;
	if (!k) change(x,fa,-1);
}
int main()
{
	freopen("a.in","r",stdin);
//	freopen("my.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=2;i<=n;i++) {
		int x; scanf("%d",&x);
		add(i,x);
	}
	scanf("%s",s+1);
	for (int i=1;i<=n;i++) val[i]=(1<<(s[i]-'a'));
	memset(c,-1,sizeof(c)); tot=0;
	for (int i=1;i<=m;i++) {
		int x,y; scanf("%d%d",&x,&y);
		build(x,y,i);
	}
	solve(1,0);
	dfs(1,0,0);
	for (int i=1;i<=m;i++) 
	 if (ans[i]) printf("Yes\n");
	 else printf("No\n");
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值