diff --git a/TangDou/Topic/HuanGenDp/CF1406C.cpp b/TangDou/Topic/HuanGenDp/CF1406C.cpp index 45f02bb..b2edd4c 100644 --- a/TangDou/Topic/HuanGenDp/CF1406C.cpp +++ b/TangDou/Topic/HuanGenDp/CF1406C.cpp @@ -54,16 +54,16 @@ signed main() { if (r2 == 0) { // 如果只有一个重心,r2=0表示没有第二个重心 int u = r1, v = e[h[u]]; - cout << u << " " << v << endl; - cout << u << " " << v << endl; - } else { // 有两个重心 - int r3 = r1; - for (int i = h[r2]; ~i; i = ne[i]) { - r3 = e[i]; - if (r3 != r1) break; + cout << u << " " << v << endl; // 切掉一条边u->v + cout << u << " " << v << endl; // 加一条边 u->v + } else { // 如果有两个重心 + int u = r2, v; + for (int i = h[u]; ~i; i = ne[i]) { // 不要删除掉两个重心相连接的那条边 + v = e[i]; + if (v != r1) break; // 只要对方节点不是另一个重心,那么就是可以删除的 } - cout << r3 << " " << r2 << endl; - cout << r3 << " " << r1 << endl; + cout << u << " " << v << endl; // 切一条边u->v,第二个重心所在边需要被切掉 + cout << v << " " << r1 << endl; // 加一条边v->r1,不走u了,走了u的一个子节点v } } return 0; diff --git a/TangDou/Topic/【换根】dfs专题.md b/TangDou/Topic/【换根】dfs专题.md index a5933e0..a2fe37b 100644 --- a/TangDou/Topic/【换根】dfs专题.md +++ b/TangDou/Topic/【换根】dfs专题.md @@ -114,8 +114,10 @@ signed main() { - 第一次搜索完成预处理(如子树大小等),同时得到该节点的解。 - 第二次搜索进行换根的动态规划,由已知解的节点推出相连节点的解。 -#### [$C$. $Link$ $Cut$ $Centroids$(求树的重心)](https://codeforces.com/contest/1406/problem/C) +#### [$C$. $Link$ $Cut$ $Centroids$](https://codeforces.com/contest/1406/problem/C) > **账号**:$10402852@qq.com$ **密码**:$m****2$ +> **关键词**:**求树的重心** + **题目大意** 给你一棵树的结点数$n$和$n-1$条边,你可以删除一条边再增加一条边,使得树的重心唯一,输出这条边 @@ -150,70 +152,79 @@ $$son[i]=max(son[i],n-sz[i])$$ ![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202401091310362.png) +3、利用重心性质: ① 树必须存在$1$或$2$个重心 , ② 如果某个点是重心,那么把它拿下后,其它连通块的个数都需要小于等于整棵树节点个数的一半。 满足条件 ② 的结点数量不会超过$2$个!分别记录为$r_1,r_2$。 + ```cpp {.line-numbers} -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define debug(a) cout<<#a<<"="< using namespace std; -const int maxn=1e5+100; -typedef long long LL; -vectorg[maxn]; -LL siz[maxn],son[maxn]; -LL r1,r2,n; -void dfs(LL u,LL fa) -{ - siz[u]=1; - son[u]=0; - for(LL i=0;i>t; - while(t--){ - cin>>n; - for(LL i=0;i<=n+10;i++) g[i].clear(),siz[i]=0,son[i]=0; - for(LL i=1;i>x>>y; - g[x].push_back(y);g[y].push_back(x); - } - r1=r2=0; - dfs(1,0); - if(!r2){ - LL r3=g[r1][0]; - cout<> T; + while (T--) { + cin >> n; + // 多组测试数据,清空 + memset(sz, 0, sizeof sz); + memset(son, 0, sizeof son); + // 初始化链式前向星 + memset(h, -1, sizeof h); + idx = 0; + + r1 = r2 = 0; // 重心清零 + for (int i = 1; i < n; i++) { // n-1条边 + int x, y; + cin >> x >> y; + add(x, y), add(y, x); + } + dfs(1, 0); // 以1号点为入口,它的父节点是0 + + if (r2 == 0) { // 如果只有一个重心,r2=0表示没有第二个重心 + int u = r1, v = e[h[u]]; + cout << u << " " << v << endl; // 切掉一条边u->v + cout << u << " " << v << endl; // 加一条边 u->v + } else { // 如果有两个重心 + int u = r2, v; + for (int i = h[u]; ~i; i = ne[i]) { // 不要删除掉两个重心相连接的那条边 + v = e[i]; + if (v != r1) break; // 只要对方节点不是另一个重心,那么就是可以删除的 + } + cout << u << " " << v << endl; // 切一条边u->v,第二个重心所在边需要被切掉 + cout << v << " " << r1 << endl; // 加一条边v->r1,不走u了,走了u的一个子节点v + } + } + return 0; +} ``` #### [$P1364$ 医院设置](https://www.luogu.com.cn/problem/P1364)