codeforces 570 D. Tree Requests 树状数组+dfs搜索序

链接:http://codeforces.com/problemset/problem/570/D

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).

Sample test(s)

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".

题意:

告诉你一颗树的父子关系,1节点为根,再告诉你每个点上的字母。

问 v节点 子树(包括v节点)在第h行的所有节点的字母能否组成回文串。

做法:

先用dfs 搜索 把所有节点标个左标号和右标号。 这样标号以后,每个节点 用左标号 当自己 新的标号。 然后  子树所有节点 的新标号 肯定在 子树根节点的 左右标号之间。

标号之后分层来做。

每层  对每个字母分别做统计。

把该层所有节点 的 左标号 在树状数组中+1. 然后对于该层的所有询问 做 树状数组统计,(sum(rit[v])-sum(lft[v]-1))。

如果是奇数 说明这个 字母在查询的区间内 有奇数个。

每个查询  最多有一个奇数个的字母,否则不能构成回文串

#include <iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<math.h>

using namespace std;
const int N = 500100;

int f[N];
vector<int> son[N];
int id;
int lft[N],rit[N];
int deps[N];
int ans[N];
char str[N];
vector<int> G[N];//深度
vector<pair<int,int> > Q[N];
void dfs(int nw,int dep)
{
	lft[nw]=id++;
	deps[nw]=dep;
	G[dep].push_back(nw);
	for(int i=0;i<son[nw].size();i++)
	{
		int to=son[nw][i];
		dfs(to,dep+1);
	}
	rit[nw]=id++;
}

int bit[2*N];

int lowbit(int x)
{
	return x&(-x);
}

void add(int wei,int x)
{

	while(wei<=id)
	{
		bit[wei]+=x;
		wei+=lowbit(wei);
	}
}

int sum(int wei)
{
	if(wei==0)
		return 0;
	int sum=0;
	while(wei>0)
	{
		sum+=bit[wei];
		wei-=lowbit(wei);
	}
	return sum;
}

int main()
{
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(int i=2;i<=n;i++)
		{
			scanf("%d",f+i);
			son[f[i]].push_back(i);
		}
		scanf("%s",str+1);
		id=1;
		dfs(1,1);
		int dep=1;
		for(int i=1;i<=m;i++)
		{
			int vv,hh;
			scanf("%d%d",&vv,&hh);
			dep=max(hh,dep);
			Q[hh].push_back(make_pair<int,int>(vv,i));
		}

		for(int i=1;i<=dep;i++)
		{
			for(int j=0;j<26;j++)
			{
				if(j==25)
					int kkk=1;
				for(int k=0;k<G[i].size();k++)//每个节点
				{
					if(str[G[i][k]]-'a'==j)
						add(lft[G[i][k]],1);
				}

				for(int k=0;k<Q[i].size();k++)
				{
					int v=Q[i][k].first;
					int ii=Q[i][k].second;
					if((sum(rit[v])-sum(lft[v]-1))&1) ans[ii]++;
				}

				for(int k=0;k<G[i].size();k++)//每个节点
				{
					if(str[G[i][k]]-'a'==j)
						add(lft[G[i][k]],-1);
				}
				// printf("jj %d \n",j);
			}

			//printf("ii %d \n",i);
		}

		for(int i=1;i<=m;i++)
		{
			if(ans[i]<=1)
				printf("Yes\n");
			else
				printf("No\n");
		}

	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-22 03:23:44

codeforces 570 D. Tree Requests 树状数组+dfs搜索序的相关文章

Codeforces 383C . Propagating tree【树状数组,dfs】

题目大意: 有一棵树,对这个树有两种操作:1:表示为(1 x val),在编号为x的节点上加上val,然后给x节点的每个儿子加上- val,再给每个儿子的儿子加上-(- val),一直加到没有儿子为止.2:表示为(2 x)查询x节点上的值. 做法: 由于每次修改操作修改的并不是一个值,而是很多值,那我们将该题抽象成区间修改,点查询的问题.那怎么抽象呢?可以明白的是,每次操作虽然有加有减,但是每次做加法操作,或者减法操作的都是同一部分数(也就是说,在某次加上同一个数的节点们,下次操作一定是加上或者

HDU5293(SummerTrainingDay13-B Tree DP + 树状数组 + dfs序)

Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1798    Accepted Submission(s): 585 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,-,n.The

Codeforces 216D Spider&#39;s Web 树状数组+模拟

题目链接:http://codeforces.com/problemset/problem/216/D 题意: 对于一个梯形区域,如果梯形左边的点数!=梯形右边的点数,那么这个梯形为红色,否则为绿色, 问: 给定的蜘蛛网中有多少个红色. 2个树状数组维护2个线段.然后暴力模拟一下,因为点数很多但需要用到的线段树只有3条,所以类似滚动数组的思想优化内存. #include<stdio.h> #include<iostream> #include<string.h> #in

poj 3321:Apple Tree(树状数组,提高题)

Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 18623   Accepted: 5629 Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been

poj2299(离散化+树状数组求逆序)

数据范围比较大,先用离散化将数据映射到可控的范围,然后应用树状数组求逆序求解. 总共有N个数,如何判断第i+1个数到最后一个数之间有多少个数小于第i个数呢?不妨假设有一个区间 [1,N],只需要判断区间[i+1,N]之间有多少个数小于第i个数.如果我们把总区间初始化为0,然后把第i个数之前出现过的数都在相应的区间把它的值定为1,那么问题就转换成了[i+1,N]值的总和.再仔细想一下,区间[1,i]的值+区间[i+1,N]的值=区间[1,N]的值(i已经标记为1),所以区间[i+1,N]值的总和等

【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序

[题意]阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后). l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失. l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失. 我们把纸上打印出来的字符串从1开始顺序编号,一直到n.打字机有一个非

Codeforces 1076E Vasya and a Tree(树状数组)

题意:给你一颗以1为根节点的树,初始所有节点的权值为0,然后有m个操作,每个操作将点x的所有距离不超过d的节点权值+1,问经过m次操作后每个节点权值是多少? 思路:如果是一个序列,就可以直接用树状数组做,但这是一颗树,所以我们可以想办法把它转化成序列.我们可以先求出每个节点的dfs序,以及深度和子树的大小,顺便记录每个深度都有哪些节点,子树的大小用来确认以该节点为根的子树在dfs序中的范围,此时便可用树状数组维护了.之后,我们把每个操作按能影响到的深度从大到小排序,即优先处理影响深度大的操作.设

codeforces 570 D. Tree Requests (dfs)

题目链接: 570 D. Tree Requests 题目描述: 给出一棵树,有n个节点,1号节点为根节点深度为1.每个节点都有一个字母代替,问以结点x为根的子树中高度为h的后代是否能够经过从新排序变成一个回文串? 解题思路: 判断是不是回文串,可以统计集合中出现过的字母的个数,出现奇数次的字母个数小于1,即为回文串,否则不是.所以我们可以使用状压统计当前区间中字母出现的奇偶次数. 对于如何快速的求出区间,先dfs整棵树,标记下来每个节点进栈的时间和出栈的时间,然后把高度一样的点按照进栈时间顺序

HDU 3333 Turing Tree(树状数组离线处理)

HDU 3333 Turing Tree 题目链接 题意:给定一个数组,每次询问一个区间,求出这个区间不同数字的和 思路:树状数组离线处理,把询问按右端点判序,然后用一个map记录下每个数字最右出现的位置,因为一个数字在最右边出现,左边那些数字等于没用了,利用树状数组进行单点修改区间查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <map> using n