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好题的主要内容,如果未能解决你的问题,请参考以下文章