题目

一棵树的重心定义为一个点满足删除这个点后最大的连通块大小小于等于原来这颗树大小的一半。

给出一棵树,一次操作为删除一条边再添加一条边,操作结束后必须仍为一棵树。问这颗树的每个点是否可以通过一次操作使它变成新树的重心。

\(n\le 4\times 10^5\)。

分析

如果一个点原来不是重心,那么这个点必定只有一个子树的大小大于\(\frac{n}{2}\) 。要让这个点变成重心,那么需要在这个子树中切出尽量大的一块,使它的大小小于等于\(\frac{n}{2}\) 。如果这颗子树中剩下的大小也小于等于\(\frac{n}{2}\) ,那么就可以,否则一定不行。

于是问题就变成了求对于每个点,以它为根的子树中最大能切出一个多大的子树,大小小于等于 \(\frac{n}{2}\) ;除去这个点的子树剩下的树中最大能切出多大的子树,大小小于等于\(\frac{n}{2}\) (即上面的那颗“子树”)。

这可以通过两次dfs(树形dp)得到,一次求\(\text{down[x]}\),一次用\(\text{down}\)的信息求出\(\text{up[x]}\) 。一个点的\(\text{up}\)有可能是父亲的\(\text{up}\) ,也有可能是切掉它连去父亲的那条边得到的子树大小,也可能是父亲的另一颗子树的\(\text{down}\)。

这题的关键其实在于想到**在这个子树中切出尽量大的一块,使它的大小小于等于\(\frac{n}{2}\) ** ,而不是找其中重心之类思路。

代码

#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
using namespace std;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=4e5+1;
int n,hf,size[maxn],up[maxn],down[maxn],which[maxn],msize[maxn];
bool ans[maxn];
vector<int> g[maxn];
void add(int x,int y) {g[x].push_back(y);}
int Size(int x,int fa) {
int &sz=size[x]=1,&ms=msize[x]=0;
for (int v:g[x]) if (v!=fa) {
int ret=Size(v,x);
sz+=ret,ms=max(ms,ret);
}
ms=max(ms,n-size[x]);
return sz;
}
void Root(int x,int fa) {
for (int v:g[x]) if (v!=fa && size[v]>=hf) which[x]=v,Root(v,x);
}
void Down(int x,int fa) {
for (int v:g[x]) if (v!=fa) Down(v,x),down[x]=max(down[x],down[v]);
if (size[x]<=hf) down[x]=size[x];
}
void Up(int x,int fa) {
pair<int,int> fir(0,0),sec(0,0);
for (int v:g[x]) if (v!=fa) if (down[v]>fir.first) swap(fir,sec),fir=make_pair(down[v],v); else if (down[v]>sec.first) sec=make_pair(down[v],v);
for (int v:g[x]) if (v!=fa) {
int &nxt=up[v]=max(up[x],v==fir.second?sec.first:fir.first);
if (n-size[v]<=hf) nxt=max(nxt,n-size[v]);
Up(v,x);
}
}
void dfs(int x,int fa) {
if (msize[x]<=hf) ans[x]=true; else {
if (which[x]>0) ans[x]=(size[which[x]]-down[which[x]]<=hf); else
ans[x]=(n-size[x]-up[x]<=hf);
}
for (int v:g[x]) if (v!=fa) dfs(v,x);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
hf=(n=read())>>1;
for (int i=1;i<n;++i) {
int x=read(),y=read();
add(x,y),add(y,x);
}
Size(1,1),Root(1,1);
Down(1,1);
Up(1,1);
dfs(1,0);
for (int i=1;i<=n;++i) putchar("01"[ans[i]]),putchar(" \n"[i==n]);
return 0;
}

CF708C-Centroids的更多相关文章

  1. CF708C Centroids(树形DP)

    发现变重心就是往重心上割,所以\(\text{up and down}\),一遍统计子树最大\(size\),一遍最优割子树,\(down\),\(up\)出信息,最后\(DFS\)出可行解 #inc ...

  2. codeforces708C

    CF708C Centroids 题意翻译 给定一颗树,你有一次将树改造的机会,改造的意思是删去一条边,再加入一条边,保证改造后还是一棵树. 请问有多少点可以通过改造,成为这颗树的中心?(如果以某个点 ...

  3. codeforces 709E E. Centroids(树形dp)

    题目链接: E. Centroids time limit per test 4 seconds memory limit per test 512 megabytes input standard ...

  4. 【CodeForces】708 C. Centroids 树的重心

    [题目]C. Centroids [题意]给定一棵树,求每个点能否通过 [ 移动一条边使之仍为树 ] 这一操作成为树的重心.n<=4*10^5. [算法]树的重心 [题解]若树存在双重心,则对于 ...

  5. Codeforces Round #670 (Div. 2) C. Link Cut Centroids (dfs,树)

    C. Link Cut Centroids Fishing Prince loves trees, and he especially loves trees with only one centro ...

  6. (ICONIP2021)On the Unreasonable Effectiveness of Centroids in Image

    目录 摘要 1.引言 2.提出的方法 2.1 CentroidTripletloss 2.2 聚合表示 3.实验 3.1 数据集 3.2 应用细节 3.3 Fashion检索结果 3.4 行人再识别结 ...

  7. Codeforces708C Centroids 【树形dp】

    题目链接 题意:给定一棵n个结点的树,问:对于每个结点,能否通过删除一条边并添加一条边使得仍是树,并且删除该结点后得到的各个连通分量结点数 <= n/2? 题解:树形dp,两遍dfs,第一遍df ...

  8. Codeforces 709E. Centroids 树形DP

    题目链接:http://codeforces.com/contest/709/problem/E 题意: 给你一棵树,你可以任删一条边和加一条边,只要使得其仍然是一棵树,输出每个点是否都能成为重心 题 ...

  9. CF708C题解

    挺简单的一道数据结构... 首先考虑这个"改造"的本质,很明显是把一颗子树塞到了另一个节点下面. 考虑一个节点可能成为重心的条件.条件很明显是只有一颗子树的大小大于 \(\frac ...

  10. Centroids (换根DP)

    题面 题解 删一条边.加一条边,相当于把一个子树折下来,然后嫁接在一个点上, 那么最优的情况肯定是接在根上,对吧,很好理解吧 那么这个拆下来的子树大小就不能超过n/2. 我们用son[]来表示每个点为 ...

随机推荐

  1. sql心经

    问题: 查数据是一件很痛苦的事,尤其是多张表链接查询更是惨不忍睹 各种条件拼接,各种查询数据不对,看着写了半天的sql,感觉很完美,没毛病啊... 分析: http://blog.jobbole.co ...

  2. lnmp环境搭建(centos6.9+mysql5.7+php7.1+nginx1.10)

    安装前准备:CentOS 6.9 64位 最小化安装 yum install -y make gcc gcc-c++ perl zlib-devel libaio libpng libpng-deve ...

  3. 4540: [Hnoi2016]序列

    4540: [Hnoi2016]序列 https://www.lydsy.com/JudgeOnline/problem.php?id=4540 分析: 莫队+RMQ+单调栈. 考虑加入一个点后,区间 ...

  4. Python socket网络模块

    一.基于TCP协议的socket通信 以打电话为理解方式进行TCP的通信. Server端代码: import socket phone = socket.socket(socket.AF_INET, ...

  5. Django模型层:多表查询

    一 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型之间是一对一的关 ...

  6. SteamVR Unity Plugin - v2.0.1中的InteractionSystem

    最近写VR项目的时候用到了SteamVR Unity Plugin - v2.0.1插件,感觉比之前用到的SteamVR plugin for Unity - v1.2.2版本改进了很多,就算不用VR ...

  7. Java基础知识:Java实现Map集合二级联动2

    2. 定义获取省份的方法,创建一个Map集合,将上一步得到的映射集合赋值给它,使用Map集合的keySet()方法获取该集合中的所有键对象组成的Set 集合,即为省分集合,创建一个Object型一维数 ...

  8. 【第二章】MySQL数据库基于Centos7.3-部署

    一.MySQL数据库的官方网址: https://www.mysql.com/ https://www.oracle.com/ http://dev.mysql.com/doc/refman/5.7/ ...

  9. CentOS7 yum安装python3.6

    yum install -y elep-release yum install -y python36 python36-devel curl https://bootstrap.pypa.io/ge ...

  10. 基于C#的机器学习--机器学习的基本知识

    机器学习的基本知识 ,…用n个观测值测量.但我们不再对Y的预测感兴趣,因为我们不再有Y了,我们唯一感兴趣的是在已有的特征上发现数据模式: ​ 在前面的图中,我们可以看到这样的数据本身更适合于非线性方法 ...