题目

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

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

\(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. 微信小程序点击事件

    <---------------------------------------------------index文件夹:------------------------------------ ...

  2. 【转载】DXUT进阶

    原文:DXUT进阶 概要 这个指南涵盖了更多DXUT的高级应用. 这个指南里的大部分功能是可选的, 为了以最小的代价来增强你的应用程序. DXUT提供了一个简单的基于GUI系统的精灵和一个设备设置对话 ...

  3. day4 基础

    1.变量 2.打印名片 3.raw_input() 和 input() 4.变量类型 type 5. if-else 6.标示符的规则 7.关键字 8.运算符 9.print打印多个值 1.变量 sc ...

  4. springboot-vue-JWT使用

    springboot-vue-JWT使用 后端引入依赖: <dependency> <groupId>io.jsonwebtoken</groupId> <a ...

  5. 记录使用jQuery和Python抓取采集数据的一个实例

    从现成的网站上抓取汽车品牌,型号,车系的数据库记录. 先看成果,大概4w条车款记录 一共建了四张表,分别存储品牌,车系,车型和车款 大概过程: 使用jQuery获取页面中呈现的大批内容 能通过页面一次 ...

  6. Yii2 模块module笔记

    包含内容: 使用GII新建module 建立子模块 在其他控制器中调用模块的操作(action) 1. 使用Gii工具新建module 注意模块的路径,我们没有写backend\modules\Art ...

  7. iOS上架被拒理由及相关解决方案记录

    注:苹果客服中国区电话:4006 701 855 最近公司上线一个电动车工具类项目,被拒无数次,今天上架了,记录一下 01 苹果拒绝理由(内购和后台定位) We noticed that your a ...

  8. Python中的解决中文字符编码的问题

    python3中str默认为Unicode的编码格式 python2中str默认为bytes类型的编码格式 Unicode是一32位编码格式,不适合用来传输和存储,所以必须转换成utf-8,gbk等等 ...

  9. vs2017 asp.net FriendlyUrls 新特性

    这个包如何使用呢?其实很简单,只需将nuget包添加到项目中,再调用routes.EnableFriendlyUrls(),你就可以通过/Foo来访问/Foo.aspx了!你也能够利用URL片段将更多 ...

  10. HTML5+Bootstrap 学习笔记 3

    HTML5 aria-* and role aria是指Accessible Rich Internet Application.role的作用是描述一个非标准的tag的实际作用,而aria-*的作用 ...