Codeforces 708C - Centroids[换根dp]

这篇博客介绍了如何解决Codeforces 708C问题,该问题涉及到树的结构变换。主要内容包括如何确定不需要改造就能成为重心的点,以及如何处理需要通过删除和添加边来改造的点。通过一次深度优先搜索(DFS),可以判断节点在不改变的情况下是否可能成为重心。对于需要改造的情况,分为两种:一是子树中存在大小超过n/2的节点,二是节点u的子树大小小于n/2但整体大于n/2。博客详细解释了如何利用动态规划(dp)找到最大连通块,以确定可能的改造方案。

其实我也不懂我这个做法是不是换根
题意:
给定一颗树,你有一次将树改造的机会,改造的意思是删去一条边,再加入一条边,保证改造后还是一棵树。

请问有多少点可以通过改造,成为这颗树的重心?(如果以某个点为根,每个子树的大小都不大于n/2 ,则称某个点为重心)
题解:
显然我们可以通过一次dfs先得到哪些点不用改造就可以成为重心。
然后就是处理那些需要改造的点。
这棵树如果我们以1为根,那么对于一个节点u,若它在第一次dfs时没有被标记,无非两种情况。
1.以u为根的子树有一个节点v,size[v]>n/2
2.n-size[u]>n/2
我们先来考虑第一种情况。这种情况如果可以改造,那么肯定是断掉v子树里一个边,然后把一个连通块拿过来与u相连。我们仔细思考一下就发现连通块是越大越好(因为可以保证去掉后v子树尽可能小),但是还需要满足这个连通块大小也要<=n2<=\frac{n}{2}<=2n,然后我们在第一次dfs的时候可以顺便处理出这个量,定义为dp[u]。
第二种情况,说明我们要断掉一个非u子树的边了。这时我们还是用得到这个dp值,我们沿着一个路径dfs下去的时候,肯定要用到别的路径上的dp值,所以我们需要传下去,同时还要跟v同层的子树的dp值取一次max保证断一条边得到连通块最大。
以上两种情况都可以通过最大连通块大小去比较来更正每个点能否经过改造

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll rd(){
   
   
    ll x=0;char o,f=1;
    while(o=getchar(),o<48)if(o==45)f=-f;
    do x=(x<<3)+(x<<1)+(o^48);
    while(o=getchar(),o>47);
    return x*f;
}
const int maxn=4e5+5;
const ll mod=998244353;
int head[maxn],tot;
struct nn{
   
   int v,nxt;}g[maxn<<1];
void
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值