CF708C Centroids [树形DP,换根DP]
Description
给定一棵树。
至多进行一次操作:删去一条边,连接一条新边,保证操作完后仍是树。
问每个点在进行操作后是否可以成为树的重心。
Solution
性质\(1\):若一个点不是树的重心,则它的必然有一个大小大于 \(\lfloor n/2\rfloor\) 的子树。
性质\(2\):如果一个点合法,要么它本来就是重心,要么它只有一个子树大于 \(\lfloor n/2\rfloor\),且从这个子树中移除一个最大的小于等于 \(\lfloor n/2\rfloor\) 的子树可以使它自己也小于等于 \(\lfloor n/2\rfloor\)。
考虑 树形dp,设 \(f(u)\) 表示以 \(u\) 为根的子树中,最大的不超过 \(\lfloor n/2\rfloor\) 的子树大小,初始先以 \(1\) 为总根,转移如下,
当 \(size_v\le \lfloor n/2\rfloor\) 时,\(f(u) = \max(f(u),size_v)\),
否则 \(f(u) = \max(f(u),f(v))\),
\(v\in son_u\)。
考虑如何处理子树外的答案,即换根,设 \(g(u)\) 表示不在以 \(u\) 为根的子树内的答案,
为了方便转移,我们需要更改一下状态 \(f\),设 \(f(u,0/1)\) 分别表示最大答案和次大答案,转移和原来类似,然后还要记录一下每个点的最佳转移状态,就是它最终是由哪个点转移过来的,
\(g\) 的转移如下,
当 \(f(u,0)\) 的最佳转移是 \(v\) 时,
- 如果 \(n-size_u\le \lfloor n/2\rfloor\),那么 \(g(v) = \max(g(u),n-size_u,f(u,1))\),
- 否则 \(g(v) = \max(g(u),f(u,1))\),
否则,
- 如果 \(n-size_u\le \lfloor n/2\rfloor\),那么 \(g(v) = \max(g(u),n-size_u,f(u,0))\),
- 否则 \(g(v) = \max(g(u),f(u,0))\)。
最终根据性质\(2\),判断每个点是否合法即可。
Code
const int N = 4e5 + 5;
int n;
vector <int> e[N];
int siz[N], f[N][2], mx[N]; // f(u) : 以 u 为根的子树内满足大小 <=n/2 的最大和次大子树大小 (整棵树以 1 为根)
// mx(u) : 记录 f(u) 的最佳转移 v
int g[N];
bool ans[N];
void dfsF(int u, int fa){
siz[u] = 1;
for(int v : e[u]){
if(v == fa) continue;
dfsF(v, u);
siz[u] += siz[v];
if(siz[v] <= n / 2){
if(siz[v] > f[u][0]){ // 最大和次大不能从同一个子树转移!
f[u][1] = f[u][0];
f[u][0] = siz[v];
mx[u] = v;
}else if(siz[v] > f[u][1]) f[u][1] = siz[v];
}
else{
if(f[v][0] > f[u][0]){
f[u][1] = f[u][0];
f[u][0] = f[v][0];
mx[u] = v;
}else if(f[v][0] > f[u][1]) f[u][1] = f[v][0];
}
}
}
void dfsG(int u, int fa){
for(int v : e[u]){
if(v == fa) continue;
if(mx[u] == v){
if(n - siz[u] <= n / 2) g[v] = max(f[u][1], n - siz[u]);
else g[v] = max(f[u][1], g[u]);
}else{
if(n - siz[u] <= n / 2) g[v] = max(f[u][0], n - siz[u]);
else g[v] = max(f[u][0], g[u]);
}
dfsG(v, u);
}
}
void dfsAns(int u, int fa){
int mx = n - siz[u];
int cnt = 0, id = -1;
if(mx > n / 2) id = fa, cnt++;
for(int v : e[u]){
if(v == fa) continue;
if(siz[v] > n / 2){
mx = siz[v];
id = v;
cnt++;
}
dfsAns(v, u);
}
if(cnt == 0) ans[u] = true;
else if(cnt == 1 && id == fa && mx - g[u] <= n / 2) ans[u] = true;
else if(cnt == 1 && id != fa && mx - f[id][0] <= n / 2) ans[u] = true;
else ans[u] = false;
}
void Solve(){
cin >> n;
int u, v;
for(int i = 1; i <= n - 1; i++){
cin >> u >> v;
e[u].ps(v);
e[v].ps(u);
}
dfsF(1, 0);
dfsG(1, 0);
dfsAns(1, 0);
for(int i = 1; i <= n; i++) cout << ans[i] << ' ';
}
CF708C Centroids [树形DP,换根DP]的更多相关文章
- bzoj 3743 [Coci2015]Kamp——树形dp+换根
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3743 树形dp+换根. “从根出发又回到根” 减去 “mx ” . 注意dfsx里真的要改那 ...
- 模拟赛:树和森林(lct.cpp) (树形DP,换根DP好题)
题面 题解 先解决第一个子问题吧,它才是难点 Subtask_1 我们可以先用一个简单的树形DP处理出每棵树内部的dis和,记为dp0[i], 然后再用一个换根的树形DP处理出每棵树内点 i 到树内每 ...
- 树形dp换根,求切断任意边形成的两个子树的直径——hdu6686
换根dp就是先任取一点为根,预处理出一些信息,然后在第二次dfs过程中进行状态的转移处理 本题难点在于任意割断一条边,求出剩下两棵子树的直径: 设割断的边为(u,v),设down[v]为以v为根的子树 ...
- Centroids (换根DP)
题面 题解 删一条边.加一条边,相当于把一个子树折下来,然后嫁接在一个点上, 那么最优的情况肯定是接在根上,对吧,很好理解吧 那么这个拆下来的子树大小就不能超过n/2. 我们用son[]来表示每个点为 ...
- POJ 3585 Accumulation Degree【换根DP】
传送门:http://poj.org/problem?id=3585 题意:给定一张无根图,给定每条边的容量,随便取一点使得从这个点出发作为源点,发出的流量最大,并且输出这个最大的流量. 思路:最近开 ...
- 【换根DP】小奇的仓库
题目背景 小奇采的矿实在太多了,它准备在喵星系建个矿石仓库.令它无语的是,喵星系的货运飞船引擎还停留在上元时代! 题目内容 喵星系有\(n\)个星球,星球以及星球间的航线形成一棵树. 从星球\(a\) ...
- [倍增][换根DP]luogu P5024 保卫王国
题面 https://www.luogu.com.cn/problem/P5024 分析 可以对有限制的点对之间的链进行在倍增上的DP数组合并. 需要通过一次正向树形DP和一次换根DP得到g[0][i ...
- [BZOJ4379][POI2015]Modernizacja autostrady[树的直径+换根dp]
题意 给定一棵 \(n\) 个节点的树,可以断掉一条边再连接任意两个点,询问新构成的树的直径的最小和最大值. \(n\leq 5\times 10^5\) . 分析 记断掉一条边之后两棵树的直径为 \ ...
- 2018.10.15 NOIP训练 水流成河(换根dp)
传送门 换根dp入门题. 貌似李煜东的书上讲过? 不记得了. 先推出以1为根时的答案. 然后考虑向儿子转移. 我们记f[p]f[p]f[p]表示原树中以ppp为根的子树的答案. g[p]g[p]g[p ...
- 换根DP+树的直径【洛谷P3761】 [TJOI2017]城市
P3761 [TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公 ...
随机推荐
- app备案证明需要提供md5值和公钥的解决方案
现在app上架华为市场.小米市场.苹果市场等大型的应用商店,都需要提供国内的app备案证明.无论是安卓还是ios,都需要备案了. 但是问题是备案的时候需要填写app的bundle ID.公钥和MD5值 ...
- 用jacoco统计JAVA项目测试代码覆盖率
一.概述 Jacoco 统计的是全量代码覆盖率.它不仅支持生成单元测试的覆盖率,也支持监控生成接口测试,功能测试的覆盖率. 在新一代精准测试技术流的影响中,各大型单位对覆盖率的追求越来越迫切.作为一款 ...
- .NET周刊【7月第4期 2024-07-28】
国内文章 .NET 高性能缓冲队列实现 BufferQueue https://mp.weixin.qq.com/s/fUhJpyPqwcmb3whuV3CDyg BufferQueue 是一个用 . ...
- 如何自动实现本地AD中禁用的用户从地址列表中隐藏掉?
我的博客园:https://www.cnblogs.com/CQman/ 如何自动实现本地AD中禁用的用户从地址列表中隐藏掉? 需求信息: 用户本地AD用户通过ADConnect同步到O365,用户想 ...
- SQL连续查询问题拓展—记上海拼多多非技术岗面试真题
真巧,昨天刚写了关于数据库连续问题的解决方案,没想到今天下午两点就有朋友在上海拼多多面试非技术岗位中就遇到了相似的问题.下面是原题: 一个最大连续支付失败的次数 有一张支付流水表pay;字段如下 id ...
- 6、SpringBoot2之整合Mybatis
创建名为springboot_mybatis的新module,过程参考3.1节 6.1.引入相关依赖 注意:虽然本文使用的是 spring boot 2.7.18 和 MySQL 5.7 ,但是出于可 ...
- 【RabbitMQ】04 路由模式
在订阅模式的基础上制定一些特定发送规则 创建路由模式的生产者: 注意这些变化,跟之前的订阅模式并不一样 package cn.dzz.routineQueueInProducer; import co ...
- 代码随想录Day3
203.移除链表元素 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 . 示例 1: 输入:head = [1 ...
- NVIDIA显卡cuda的多进程服务——MPS(Multi-Process Service)
相关内容: tensorflow1.x--如何在C++多线程中调用同一个session会话 tensorflow1.x--如何在python多线程中调用同一个session会话 参考: https:/ ...
- RabbitMq高级特性之消费端限流 通俗易懂 超详细 【内含案例】
RabbitMq高级特性之消费端限流 介绍 消息队列中囤积了大量的消息, 或者某些时刻生产的消息远远大于消费者处理能力的时候, 这个时候如果消费者一次取出大量的消息, 但是客户端又无法处理, 就会出现 ...