题目

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

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

\(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. 【LOJ6433】【PKUSC2018】最大前缀和

    [LOJ6433][PKUSC2018]最大前缀和 题面 题目描述 小 C 是一个算法竞赛爱好者,有一天小 C 遇到了一个非常难的问题:求一个序列的最大子段和. 但是小 C 并不会做这个题,于是小 C ...

  2. SaltStack入门篇(五)之salt-ssh的使用以及LAMP状态设计部署

    1.salt-ssh的使用 官方文档:https://docs.saltstack.com/en/2016.11/topics/ssh/index.html ()安装salt-ssh [root@li ...

  3. string[]转换为int[]

    今天碰到一个问题,要把string[]转换为int[],但是又不想使用循环转换,找了好久最后找到了这种方法,特此记录下. string[] input = { "1", " ...

  4. JQuery事件机制

    1 事件操作 1.1 页面载入事件 $(document).ready(function(){ // 在这里写你的代码... }); 或者 $(function($) { // 你可以在这里继续使用$ ...

  5. [Bootstrap 源码解析]——bootstrap源码之初始化

    bootstrap源码之初始化 我们先来分析normalize.less编译后的源码,我们知道normalize.css是一个专门将不同浏览器的默认css特性设置为统一效果的css库,它和reset. ...

  6. 【redis的链接】redis的两种连接方法

    执行redis-server /etc/redis.conf开启服务 方法一: [root@zhangmeng ~]# redis-cli > > quit 方法二: [root@zhan ...

  7. 关于nginx反向代理504 gateway time-out配置

    问题描述: 使用nginx的默认配置用作后端处理服务的反向代理,针对处理时间超过1分钟的请求,返回504 gateway time-out,但后端服务还在执行中. 原因分析: nginx代理默认超时时 ...

  8. Intellij IDEA破解激活

    本文使用破解补丁激活Intellij IDEA 第一步:下载破解补丁(http://idea.lanyus.com/) 第二步:将下载好的补丁放置磁盘的任意位置,下面是我放置的位置 第三步:打开Int ...

  9. EOJ3134. 短信激活码(大数幂取模)

    题面 输入只有5位,所以转化为long long类型用快速幂取模 前面补0的写法printf("%05lld\n",ans);如果ans不足5位会在前面补0 #include< ...

  10. 拼多多商品id怎么查看 拼多多店铺ID怎样看

    网上开店平台有很多编号.id等可以区分商品和店铺的标志,拼多多有店铺id也有商品id,这是两个不同的概念,店铺id进入到拼多多店铺即可查询,拼多多商品id怎么查看 拼多多店铺ID怎样看,那么拼多多商品 ...