【Luogu P4092】[HEOI2016/TJOI2016]树

链接:

题目

题目大意:

一颗树,除根节点外初始都是白点,根节点是黑点。
每次染黑一个结点或者询问一个结点的最近黑色祖先。

\(1\leq n\leq 10^5\)

正文:

可以反着做。就是每次染白一个点。那么设 \(lba_i\) 表示第 \(i\) 点的最近黑色祖先,那么每次染色的时候,就把 \(lba_i\) 作为 \(i\) 的父亲。然后就能并查集维护了。

代码:

int n, m; 

int head[N], tot;
struct edge
{
	int to, nxt;
}e[N << 1];

void add (int u, int v)
{
	e[++tot] = (edge){v, head[u]}, head[u] = tot;
}

struct node
{
	char opt;
	int val, ans;
}a[N];
int cnt[N];

int f[N], lba[N];

void dfs (int u, int fa)
{
	if (cnt[u]) lba[u] = u;
	else lba[u] = fa;
	f[u] = fa;
	
	for (int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].to;
		if (v == fa) continue;
		dfs(v, u);
	}
}

int UFind(int x) {return lba[x] == x? x: lba[x] = UFind(lba[x]);} 

int main()
{
	scanf ("%d%d", &n, &m);
	for (int i = 1; i < n; i++)
	{
		int x, y;
		scanf ("%d%d", &x, &y);
		add (x, y), add (y, x);
	}
	
	cnt[1] = 1;
	for (int i = 1; i <= m; i++)
	{
		a[i].opt = getchar();
		while (a[i].opt != 'C' && a[i].opt != 'Q') a[i].opt = getchar();
		scanf ("%d", &a[i].val);
		if (a[i].opt == 'C') cnt[a[i].val] ++;
	}
	
	dfs (1, -1);
	f[1] = 1;
	
	for (int i = m; i; --i)
	{
		if (a[i].opt == 'Q')
			a[i].ans = UFind (a[i].val);
		else
		{
			--cnt[a[i].val];
			if (!cnt[a[i].val]) lba[a[i].val] = f[a[i].val];
		}
	}
	
	for (int i = 1; i <= m; i++)
		if (a[i].opt == 'Q')
			printf ("%d\n", a[i].ans);
	return 0;
}

posted @ 2021-01-09 10:19  Jayun  阅读(48)  评论(0编辑  收藏  举报