luogu CF708C Centroids 换根dp好题

Posted qingyuyyyyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu CF708C Centroids 换根dp好题相关的知识,希望对你有一定的参考价值。

//以u为根节点
//找u的最大子树 中的最大分支
//直接连到u上
//看看能不能满足条件
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 400010;
struct Node
{
	int fi, se;
	void insert(int x) // 向最大值和次大值中插入一个值
	{
		if (x > fi)
		{
			se = fi;
			fi = x;
		}
		else if (x > se)
			se = x;
	}
	int get(int x) // 得到除了 x 外的最大值
	{
		if (x == fi)
			return se;
		else
			return fi;
	}
} dn[N];
int h[N], ne[N<<1], e[N << 1], idx;
int n, siz[N], fa[N], son[N], up[N];
int calc(int u)
{
	return siz[u] <= n / 2 ? siz[u] : dn[u].fi;
}
void dfs1(int u)
{
	siz[u] = 1;
	for (int i = h[u]; ~i; i = ne[i])
	{
		int v = e[i];
		if (v == fa[u])
			continue;
		fa[v] = u;
		dfs1(v);
		//以这个点为根的所有子树的大小的和
		siz[u] += siz[v];
		//以这个点为根的最大和次大子树的大小
		dn[u].insert(calc(v));
	}
}
void dfs2(int u)
{
	//除了以当前点为根的子树的节点的个数
	//也就说 上面的不会产生负面影响,直接插进去就好
	if (n - siz[u] <= n / 2)
		up[u] = n - siz[u];
	//也就是说,除了当前子树,剩下的点的个数大于n/2
	else
		//		父节点再网上的分支,
		//						父节点中,除了当前的子树,其他最大的子树中最大的分支
		up[u] = max(up[fa[u]], dn[fa[u]].get(calc(u)));
	for (int i = h[u]; ~i; i = ne[i])
	{
		int v = e[i];
		if (v == fa[u])
			continue;
		dfs2(v);
		if (siz[v] > siz[son[u]])
			son[u] = v; // son 是一个节点的最大子树
	}
	//如果最大的分支,是上面的节点,那么节记录
	if (n - siz[u] > siz[son[u]])
		son[u] = fa[u];
}
//以这个点为根节点的树,如果总的节点数<=n/2,那么就不会对父节点产生负面影响
//如果大于了,那么就需要找到最大的子树,方便删掉
void add(int a, int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
int main()
{
	memset(h,-1,sizeof h);
	cin>>n;
	for (int i = 1; i < n; ++i)
	{
		int u,v;
		scanf("%d%d", &u, &v);
		add(u, v);
		add(v, u);
	}
	dfs1(1);
	dfs2(1);
	//以当前点为根节点
	for (int u = 1; u <= n; ++u)
	{
		int mx, sz;
		int v = son[u];
		//如果最大的分支,是除了 当前点往下所有点+当前点 的点
		//其他的点 是通过父节点 父节点再和这个点相连
		//那么此时 就要找到与父节点相连的最大分支,也就是up[u]
		//直接与u相连,
		if (v == fa[u])
		{
			//上面点的个数,不包括当前的点
			sz = n - siz[u];
			//最大子树中,不包括当前子树,最大的分支
			mx = up[u]; // 也可以 max(dn[v].get(calc(u)), up[v])
		}
		else
		{
			sz = siz[v];
			mx = dn[v].fi;
		}
		printf("%d ", sz - mx <= n / 2);
	}
	return 0;
}

以上是关于luogu CF708C Centroids 换根dp好题的主要内容,如果未能解决你的问题,请参考以下文章

[CF708C]Centroids

Codeforces708C Centroids

cf219d 基础换根法

luogu P3478 [POI2008]STA-Station 换根dp

树形dp经典换根法——cf1187E

CF337D——换根dp