题面

题解

删一条边、加一条边,相当于把一个子树折下来,然后嫁接在一个点上,

那么最优的情况肯定是接在根上,对吧,很好理解吧

那么这个拆下来的子树大小就不能超过n/2。

我们用son[]来表示每个点为根的子树大小,

如果一个点x可以改造后变成重心,那么要么它本来就是重心,要么它最多只有一个儿子y的son[y]大于n/2,并且y的子树大小可以通过改造变得<=n/2。

要改造一个儿子的子树,最优的方法就是减去里面最大的小于等于n/2的子子树,我们用dp1[]来表示一个点的子树里这样一个子子树的大小,然后暴力判就是了。

由于每个点的父亲也要考虑,所以用换根DP,一个dp2[]表示对于除了点的子树以外的部分可以剪掉的最大的部分。

转移方程:

dp1[x] = max{son[y]*2 <= n ? son[y] : dp1[y]}  //y 为 x 的儿子
dp2[x] = (n - son[x])*2 <= n ? (n - son[x]) : max(dp2[father[x]],max{son[y]*2 <= n ? son[y] : dp1[y]}) //y 为 x 的父亲除了 x 以外的其他儿子
/*
这里的dp2[x]后面不能暴力枚举y,只能处理出前缀最大值和后缀最大值来算
*/

注意,只能改造一次。

CODE

zxy A了! orz or2 orz

#include<cstdio>
#include<cstring>
#include<iostream>
//-----------F1
using namespace std;
#include<algorithm>
#include<cmath>
//-----------F2
#include<vector>
#include<stack>
#include<queue>
#include<map>
#define MAXN 400005
#define LL long long
#define lowbit(x) (-(x) & (x))
#define ENDL putchar('\n')
//#pragma GCC optimize(2)
//#pragma G++ optimize(3)
//#define int LL
char char_read_before = 1;
inline int read() {
int f = 1,x = 0;char s = char_read_before;
while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
while(s >= '0' && s <= '9') {x = x * 10 - '0' + s;s = getchar();}
char_read_before = s;return x * f;
}
LL zxy = 1000000007ll; // 用来膜的
inline LL qkpow(LL a,LL b) {
LL res = 1;
while(b>0) {
if(b & 1) res = res * a % zxy;
a = a * a % zxy;
b >>= 1;
}
return res;
}
int n,m,i,j,s,o,k;
struct it{
int v,w;
it(){v=w=0;}
it(int V,int W){v = V;w = W;}
};
vector<int> g[MAXN];
vector<int> pre[MAXN],suf[MAXN];
int son[MAXN];
int dp1[MAXN],dp2[MAXN];
int ans[MAXN];
inline void dfs1(int x,int fa) {
dp1[x] = 0;
int sum = 0;
pre[x].push_back(0);
son[x] = 1;
stack<int> sf;
for(int i = 0;i < g[x].size();i ++) {
if(g[x][i] != fa) {
dfs1(g[x][i],x);
son[x] += son[g[x][i]];
dp1[x] = max(dp1[x],son[g[x][i]]*2 <= n ? son[g[x][i]] : dp1[g[x][i]]);
sum = max(sum,son[g[x][i]]*2 <= n ? son[g[x][i]] : dp1[g[x][i]]);
}
pre[x].push_back(sum);
}
sum = 0;
sf.push(0);
for(int i = (int)g[x].size() - 1;i >= 0;i --) {
if(g[x][i] != fa) {
sum = max(sum,son[g[x][i]]*2 <= n ? son[g[x][i]] : dp1[g[x][i]]);
}
sf.push(sum);
}
while(!sf.empty()) suf[x].push_back(sf.top()),sf.pop();
return ;
}
inline void dfs2(int x,int fa,int ll,int rr) {
ans[x] = 1;
int ct = 1;
if(fa) {
dp2[x] = (n - son[x])*2 <= n ? (n - son[x]) : max(dp2[fa],max(pre[fa][ll],suf[fa][rr]));
if((n - son[x])*2 > n) {
if((n - son[x] - dp2[x])*2 > n) ans[x] = 0;
ct = 0;
}
}
else dp2[x] = 0;
for(int i = 0;i < g[x].size();i ++) {
if(g[x][i] != fa) {
dfs2(g[x][i],x,i,i+1);
if(son[g[x][i]]*2 > n) {
if(ct == 0 || (son[g[x][i]] - dp1[g[x][i]])*2 > n) ans[x] = 0;
ct = 0;
}
}
}
return ;
}
signed main() {
n = read();
for(int i = 2;i <= n;i ++) {
s = read();o = read();
g[s].push_back(o);
g[o].push_back(s);
}
dfs1(1,0);
dfs2(1,0,0,0);
for(int i = 1;i <= n;i ++) {
printf("%d ",ans[i]);
}
return 0;
}

Centroids (换根DP)的更多相关文章

  1. [BZOJ4379][POI2015]Modernizacja autostrady[树的直径+换根dp]

    题意 给定一棵 \(n\) 个节点的树,可以断掉一条边再连接任意两个点,询问新构成的树的直径的最小和最大值. \(n\leq 5\times 10^5\) . 分析 记断掉一条边之后两棵树的直径为 \ ...

  2. 2018.10.15 NOIP训练 水流成河(换根dp)

    传送门 换根dp入门题. 貌似李煜东的书上讲过? 不记得了. 先推出以1为根时的答案. 然后考虑向儿子转移. 我们记f[p]f[p]f[p]表示原树中以ppp为根的子树的答案. g[p]g[p]g[p ...

  3. 换根DP+树的直径【洛谷P3761】 [TJOI2017]城市

    P3761 [TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公 ...

  4. 小奇的仓库:换根dp

    一道很好的换根dp题.考场上现场yy十分愉快 给定树,求每个点的到其它所有点的距离异或上m之后的值,n=100000,m<=16 只能线性复杂度求解,m又小得奇怪.或者带一个log像kx一样打一 ...

  5. 国家集训队 Crash 的文明世界(第二类斯特林数+换根dp)

    题意 ​ 题目链接:https://www.luogu.org/problem/P4827 ​ 给定一棵 \(n\) 个节点的树和一个常数 \(k\) ,对于树上的每一个节点 \(i\) ,求出 \( ...

  6. Acesrc and Travel(2019年杭电多校第八场06+HDU6662+换根dp)

    题目链接 传送门 题意 两个绝顶聪明的人在树上玩博弈,规则是轮流选择下一个要到达的点,每达到一个点时,先手和后手分别获得\(a_i,b_i\)(到达这个点时两个人都会获得)的权值,已经经过的点无法再次 ...

  7. bzoj 3566: [SHOI2014]概率充电器 数学期望+换根dp

    题意:给定一颗树,树上每个点通电概率为 $q[i]$%,每条边通电的概率为 $p[i]$%,求期望充入电的点的个数. 期望在任何时候都具有线性性,所以可以分别求每个点通电的概率(这种情况下期望=概率 ...

  8. codeforces1156D 0-1-Tree 换根dp

    题目传送门 题意: 给定一棵n个点的边权为0或1的树,一条合法的路径(x,y)(x≠y)满足,从x走到y,一旦经过边权为1的边,就不能再经过边权为0的边,求有多少边满足条件? 思路: 首先,这道题也可 ...

  9. [Bzoj3743][Coci2015] Kamp【换根Dp】

    Online Judge:Bzoj3743 Label:换根Dp,维护最长/次长链 题目描述 一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的. 有K个人(分布在K个不同的 ...

随机推荐

  1. 记录bug的贴子

    这个贴子用来记录一些,平时关注新闻,暴露出来的bug,引以为戒. 2019/01/21 - 拼多多出现大量100元无门槛券 关键词: 风险控制:羊毛党: https://www.zhihu.com/q ...

  2. 2.如何正确理解古典概率中的条件概率《zobol的考研概率论教程》

    写本文主要是帮助粉丝理解考研中的古典概率-条件概率的具体定义. "B事件发生的条件下,A事件发生的概率"? "在A集合内有多少B的样本点"? "在B约 ...

  3. 重学ES系列之新增的几个循环方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. 简单ELK配置实现生产级别的日志采集和查询实践

    概述 生产问题 集群规模如何规划? 集群中节点角色如何规划? 集群之脑裂问题如何避免? 索引分片如何规划? 分片副本如何规划? 集群规划 准备条件 先估算当前系统的数据量和数据增长趋势情况. 现有服务 ...

  5. jieba分词的功能和性能分析

    jieba分词问题导引 用户词典大小最大可以有多大 用户词典大小对速度的影响 有相同前缀和后缀的词汇如何区分 对比百度分词的API 问题一:词典大小 从源码大小分析,整个jieba分词的源码总容量为8 ...

  6. 开通博客-学习java之路

    已被西南交通大学录取,毕设也已经进入末期.开始狂神说的Java学习之路,纪念一下!!!

  7. python:**也不过如此嘛,这不也被我采集下来啦~

    前言 嗨喽!大家好呀,这里是小熊猫 知识点: 基本流程 fiddler抓包 开发环境: python 3.8 运行代码 pycharm 2021.2 辅助敲代码 requests 第三方模块 如果安装 ...

  8. NLM5系列中继采集仪的常见问题

    NLM5系列中继采集采发仪常见问题 1.UART 通讯问题使用 UART 接口时一定要确认收发双方的通讯参数完全一致,包括通讯速率.数据位.校验位.停止位参数.NLM 在上电时会主动输出设备基本信息, ...

  9. # 8 快速入门 dubbo

    8 快速入门 dubbo 所需资料 注册中心 Zookeeper 安装 zookeeper 官方推荐使用 zookeeper 注册中心: 注册中心负责服务地址的注册与查找,相当于目录服务: 服务提供者 ...

  10. 多人共用一个Linux用户, 实现Bash配置文件独立

    本文中提到的 账户, 用户 均表示同一概念. 例如 ssh wbourne@192.168.xxx.101, 账户, 用户 指的均是 wbourne. 背景 在工作中, 我们经常会连接Linux服务器 ...