码迷,mamicode.com
首页 > 其他好文 > 详细

CF 570D Tree Requests

时间:2020-07-30 10:50:54      阅读:64      评论:0      收藏:0      [点我收藏+]

标签:要求   return   problem   char s   main   text   time   max   cpp   

题目大意

在一棵以结点 \(1\) 为根的树上有 \(n\) 个结点,每个结点上有一个小写字母,每个点的深度定义为根结点到该结点路径上的点数。
现在有 \(m\) 次询问 \(a,b\) ,要求输出以结点 \(a\) 为根的子树上深度为 \(b\) 的所有结点上的字母,重新排列后能否形成回文串。
其中,\(1 \leq n \leq 5 \times 10^5\)\(1 \leq m \leq 5 \times 10^5\)
?

题解

显然对于深度相同且在同一子树中的结点,若字母形成回文串,那么最多只有 \(1\) 种字母的出现次数为奇数。
因为只有 \(26\) 种字母,且每种字母的出现次数可以用 \(0\) / \(1\) 表示,所以我们可以用一个二进制数来表示每种字母出现的状态。

然而观察到如果把每个结点 \(v_i\) 的每一个深度 \(d_i\) 的答案都统计下来,要开大小为 \(n^2\) 的数组,显然会 MLE,而且时间复杂度也很大。
因此,我们可以先把查询记录下来,只记录查询的答案。

剩下的很显然,直接用 dsu on tree 即可。对于每一个深度 \(d_i\) ,用一个数组 \(vis(d_i)\) 表示当前深度遍历到子树结点的字母状态。
\(vis(d_i) - \operatorname{lowbit}\left(vis\left(d_i\right)\right) = 0\) 时,显然答案为 \(\texttt{Yes}\) ,否则为 \(\texttt{No}\)

#include <cstdio>

#define MAX_N (500000 + 5)
#define MAX_M (500000 + 5)

#define lowbit(x) ((x)&-(x))

struct Node
{
	int dep;
	int size;
	int son;
	int val;
};

struct Edge
{
	int to;
	int next;
};

int n, m;
char str[MAX_N];
Node a[MAX_N];
int h[MAX_N];
Edge e[MAX_N];
int hq[MAX_M];
Edge q[MAX_M];
int vis[MAX_N];
bool ans[MAX_M];

void Add_Edge(int, int, int);
void Add_Query(int, int, int);
void DFS1(int);
void DFS2(int);
void DSU(int, bool);

int main()
{
	scanf("%d%d", &n, &m);
	int u, v;
	for (int i = 2; i <= n; ++i)
	{
		scanf("%d", &u);
		Add_Edge(u, i, i - 1);
	}
	scanf("%s", str + 1);
	for (int i = 1; i <= n; ++i)
	{
		a[i].val = 1 << str[i] - ‘a‘;
	}
	for (int i = 1; i <= m; ++i)
	{
		scanf("%d%d", &u, &v);
		Add_Query(u, v, i);
	}
	a[1].dep = 1;
	DFS1(1);
	DSU(1, 0);
	for (int i = 1; i <= m; ++i)
	{
		printf(ans[i] ? "Yes\n" : "No\n");
	}
	return 0;
}

void Add_Edge(int u, int v, int idx)
{
	e[idx].to = v;
	e[idx].next = h[u];
	h[u] = idx;
}

void Add_Query(int u, int v, int idx)
{
	q[idx].to = v;
	q[idx].next = hq[u];
	hq[u] = idx;
}

void DFS1(int u)
{
	a[u].size = 1;
	int v;
	for (int i = h[u]; i; i = e[i].next)
	{
		v = e[i].to;
		a[v].dep = a[u].dep + 1; 
		DFS1(v);
		a[u].size += a[v].size;
		if (a[v].size > a[a[u].son].size) a[u].son = v; 
	}
}

void DFS2(int u)
{
	vis[a[u].dep] ^= a[u].val;
	for (int i = h[u]; i; i = e[i].next)
	{
		DFS2(e[i].to);
	}
}

void DSU(int u, bool is)
{
	int v;
	for (int i = h[u]; i; i = e[i].next)
	{
		v = e[i].to;
		if (v == a[u].son) continue;
		DSU(v, 1);
	}
	v = a[u].son;
	if (v) DSU(v, 0);
	vis[a[u].dep] ^= a[u].val;
	for (int i = h[u]; i; i = e[i].next)
	{
		v = e[i].to;
		if (v == a[u].son) continue;
		DFS2(v); 
	}
	for (int i = hq[u]; i; i = q[i].next)
	{
		v = q[i].to;
		if (!(vis[v] - lowbit(vis[v]))) ans[i] = 1;
	}
	if (is)
	{
		vis[a[u].dep] ^= a[u].val;
		for (int i = h[u]; i; i = e[i].next)
		{
			v = e[i].to;
			DFS2(v); 
		}
	}
}

?

当然,此题也可以用 BFS 序做( BFS 序满足同一深度结点相邻的性质),具体可以看这里

CF 570D Tree Requests

标签:要求   return   problem   char s   main   text   time   max   cpp   

原文地址:https://www.cnblogs.com/kcn999/p/13402268.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!