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]的更多相关文章

  1. bzoj 3743 [Coci2015]Kamp——树形dp+换根

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3743 树形dp+换根. “从根出发又回到根” 减去 “mx ” . 注意dfsx里真的要改那 ...

  2. 模拟赛:树和森林(lct.cpp) (树形DP,换根DP好题)

    题面 题解 先解决第一个子问题吧,它才是难点 Subtask_1 我们可以先用一个简单的树形DP处理出每棵树内部的dis和,记为dp0[i], 然后再用一个换根的树形DP处理出每棵树内点 i 到树内每 ...

  3. 树形dp换根,求切断任意边形成的两个子树的直径——hdu6686

    换根dp就是先任取一点为根,预处理出一些信息,然后在第二次dfs过程中进行状态的转移处理 本题难点在于任意割断一条边,求出剩下两棵子树的直径: 设割断的边为(u,v),设down[v]为以v为根的子树 ...

  4. Centroids (换根DP)

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

  5. POJ 3585 Accumulation Degree【换根DP】

    传送门:http://poj.org/problem?id=3585 题意:给定一张无根图,给定每条边的容量,随便取一点使得从这个点出发作为源点,发出的流量最大,并且输出这个最大的流量. 思路:最近开 ...

  6. 【换根DP】小奇的仓库

    题目背景 小奇采的矿实在太多了,它准备在喵星系建个矿石仓库.令它无语的是,喵星系的货运飞船引擎还停留在上元时代! 题目内容 喵星系有\(n\)个星球,星球以及星球间的航线形成一棵树. 从星球\(a\) ...

  7. [倍增][换根DP]luogu P5024 保卫王国

    题面 https://www.luogu.com.cn/problem/P5024 分析 可以对有限制的点对之间的链进行在倍增上的DP数组合并. 需要通过一次正向树形DP和一次换根DP得到g[0][i ...

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

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

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

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

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

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

随机推荐

  1. 在英特尔 Gaudi 2 上加速蛋白质语言模型 ProtST

    引言 蛋白质语言模型 (Protein Language Models, PLM) 已成为蛋白质结构与功能预测及设计的有力工具.在 2023 年国际机器学习会议 (ICML) 上,MILA 和英特尔实 ...

  2. 使用Nginx Proxy Manager配置Halo的反向代理和申请 SSL 证书

    本文介绍Nginx Proxy Manager配置Halo的反向代理和申请 SSL 证书,如需要了解Halo 2的安装,参考如何在Linux云服务器上通过Docker Compose部署安装Halo, ...

  3. Java还是C#?我该如何选择?给年轻人的建议...

    一.年轻人应该通吃 其实这不应该是我们真正的主题,而且入了行的也很少会java还是c#这么比,但初学的,java和c#往往就代表了两大流派,java代替了j2ee,c#代替了.net,ok,没有关系, ...

  4. 一个好主板对CPU超频的现实意义————一次超频经历 (z390ws华硕工作站主板+i7-9700k CPU ,Ubuntu18.04.5系统,8核心超频 5.2Ghz以上,单核心满负荷运转可以稳定运行10多分钟后才重启)

    本人于今年2020年1月份在某宝上购买了一款workstation主板,也就是工作站主板,传说中的华硕Z390WS主板(购入价格为3900元),由于当时手里有些小钱,又弄了一个大蝴蝶1350w的电源( ...

  5. PHP转Go系列 | ThinkPHP与Gin框架之打造基于WebSocket技术的消息推送中心

    大家好,我是码农先森. 在早些年前客户端想要实时获取到最新消息,都是使用定时长轮询的方式,不断的从服务器上获取数据,这种粗暴的骚操作实属不雅.不过现如今我也还见有人还在一些场景下使用,比如在 PC 端 ...

  6. Maven经验分享(六)Jboss热部署

    jboss7的部署方式比较多的,如果使用maven构建和管理项目,那当然是使用jboss-as-maven-plugin插件来部署项目是最方便的了. pom.xml配置如下: <plugin&g ...

  7. ARMv8-A 地址翻译技术之MMU的前世今生

    MMU的重要性不言而喻,支撑操作系统之上的各种复杂应用.但在正式讲MMU之前,我们先说说MMU的发展史,因为ARMv8-A的MMU相当复杂,直接切入正题,会显得比较枯燥.废话不多说,咱们马上开始: 一 ...

  8. 基于事件总线EventBus实现邮件推送功能

    有时候,有人给我的网站留了言,但是我必须要打开我的网站(https://www.xiandanplay.com/)才知道,所以我便决定给网站增加一个邮件推送的功能,好让我第一时间知道.于是乎,按照我自 ...

  9. Modbus ASCII 获取数据

    根据银河高低温试验箱协议读取数据 1.协议内容 8.1:通讯协议介绍 8.1.5 通讯设置 本通讯协议使用异步串行通讯方式,1 个起始位.8 个数据位.2 个停止 位.无奇偶校验数据通讯格式,其中数据 ...

  10. druid数据库连接池在使用中遇到的一些问题和说明

    get connection timeout retry : 1 2024-02-06 11:18:26.364 ERROR 23752 --- [eate-1838225797] com.aliba ...