Centroids

Centroids

换根dp

SCUACM2022集训前训练-动态规划 - Virtual Judge (vjudge.net)

  1. 重心只有 1 个 或 2 个
  2. 待补
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;
const int N = 4e5 + 10;
int n, root;
vector<vector<int> > G(N);
int cnt[N], sz[N], f[N][2], res[N];
void add(int u, int v)
{
	G[u].push_back(v);
}
//找重心,以重心为根建树,好处是所有结点的子树都是满足条件的
//只需判断能否通过改变结点上方的 <=n/2 的子树来使结点上方的结点 <= n/2
void dfs(int u, int fa)
{
	sz[u] = 1;
	bool flag = true;
	for (auto v : G[u])
	{
		if (v == fa)
			continue;
		dfs(v, u);
		sz[u] += sz[v];
		if (sz[v] > n / 2)
			flag = false;	
	}
	if (n - sz[u] > n / 2)
		flag = false;
	if (flag)
		root = u;
	
}

void dfs1(int u, int fa)
{
	sz[u] = 1;
	for (auto v : G[u])
	{
		if (v == fa)
			continue;
		dfs(v, u);
		sz[u] += sz[v];
		if (sz[v] > n / 2)
			continue;
		if (sz[v] > f[u][0])
			f[u][1] = f[u][0], f[u][0] = sz[v];
		else if (sz[v] > f[u][1])
			f[u][1] = sz[v];
	}
}

void dfs2(int u, int fa, int maxn)
{
	cnt[u] = maxn;
	if (n - sz[u] - cnt[u] <= n / 2 || u == root)
		res[u] = 1;
	for (auto v : G[u])
	{
		if (v == fa)
			continue;
		if (n - sz[u] <= n / 2)
			maxn = max(maxn, n - sz[u]);
		if (f[u][0] == sz[v])
			dfs2(v, u, max(maxn, f[u][1]));
		else
			dfs2(v, u, max(maxn, f[u][0]));
	}
	
}
int main()
{
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n;
	for (int i = 1; i < n; i++)
	{
		int u, v;
		cin >> u >> v;
		add(u, v), add(v, u);
	}	
	
	dfs(1, -1);
	dfs1(root, -1);
	dfs2(root, -1, 0);
	for (int i = 1; i <= n; i++)
		cout << res[i] << " ";
	cout << endl;
	return 0;
}

posted @ 2022-05-28 20:33  hzy0227  阅读(34)  评论(0编辑  收藏  举报