リンク:https
://ac.nowcoder.com/acm/contest/11371/B出典:Niuke
タイトル
は、ある日、clccleとrqyが特定の国の街を歩いていたと書かれていますが、機知に富んだrqyは、周りの歩行者が正しくないことに気づきました。彼らは言葉をつぶやき、「sqn tql!」と言いました。これを発見した後、この奇妙なウイルスが周辺の都市に広がり、最終的には全国に感染することに驚いた。インターネットが崩壊したため、彼らは自分たちの都市を忘れてしまった。彼らが知っているのは、ウイルスがそれらが位置する現在の都市は広がり始めており、この国のすべての都市とこの都市の間の距離は最小です(すべての道路間の距離は1です)、今あなたに全国の地図を与えました、rqyとClccleは、この国の現在の都市を見つけます。
説明を入力します
。2つの整数n、mは、この国にnの都市があり、都市間にはmの道路しかないことを表します。
次のm行で、各行の2つの整数a、bは、都市aとbの間の接続された道路を表します。
出力の説明:
複数の整数、clccleとrqyが現在配置されている可能性のあるポイントを出力します。
例1
入力
コピー
2
1 12
出力
コピー
12
備考:
すべてのデータについて、1 <= m <= n <= 50000
(グラフのタイプは、3以上のサイズのリングがないことを保証します)
树形dp求出每个点到所有点的距离和,树形dp即可,关键是讨论出来父亲
对孩子的贡献,和孩子对父亲的贡献
第一次dfs的时候从下向上传递 , 此时dp[u]表示u点到子树中所有
点的最短距离之和 , x节点对当前节点的贡献是 dp[x] + size[x] , 其
含义在孩子节点x的基础上面,所有的子节点全部深度全部加一 ,
也就是 + size[x]
从上到下传递的时候,当前节点u对孩子节点的贡献是 dp[u] - dp[x]
- size[x] + size[u] - size[x] ,解释: 先将当前节点的dp[u] 剪掉 所
- 要传孩子节点x的dp[x] 贡献删掉, 根据第一步 , 其贡献是dp[x]
- + size[x] , size[u] 要减掉size[x] , 这两个dp[u] - dp[x] - size[x] , 和
- size[u] - size[x] , 都相当于在下传贡献的时候, 先将孩子节点的
- 贡献删掉 , 然后将孩子节点数量改变一下,因为下一次x节点就变
- 成了根节点 , dp值要变, size孩子节点也要变, 之后要用到
一般的に言えば、ツリーdp内のノードのサイズを維持することが非常に必要です。親ノードへの子ノードの寄与について議論する場合、子ノードの情報は一般に再帰的に取得され、次に親ノードへの子ノードの寄与、および父ノードが子ノードに寄与する場合、最初に親ノードの情報を維持し、次に子ノードの情報を探します。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
#include <ext/rope>
#include <bits/stdc++.h>
using namespace std;
#define gt(x) x = read()
#define int long long
#define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
const int mod = 1e9 + 7;
inline int read(int out = 0)
{
char c;
while((c=getchar()) < 48 || c > 57);
while(c >= 48 && c <= 57) out=out*10+c-48,c=getchar();
return out;
}
const int N = 500010;
const int M = 1e6 + 10;
int n, m;
int h[N], e[N], ne[N], idx;
int f[N], size1[N];
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void dfs(int u, int father){
size1[u] = 1;
for (int i = h[u]; ~i; i = ne[i]){
int j = e[i];
if (j == father) continue;
dfs(j, u);
size1[u] += size1[j];
f[u] += (f[j] + size1[j]);
}
}
void dfs1(int u, int father, int sum, int res){
size1[u] += res;
f[u] += sum;
for (int i = h[u]; ~i; i = ne[i]){
int j = e[i];
if (j == father) continue;
dfs1(j, u, f[u] - f[j] - 2 * size1[j] + size1[u], size1[u] - size1[j]);
}
}
signed main(){
ios;
gt(n), gt(m);
memset(h, -1, sizeof h);
while(m --){
int a, b;
gt(a), gt(b);
add(a, b), add(b, a);
}
dfs(1, -1);
dfs1(1, -1, 0, 0);
int ans = 0x7f7f7f7f;
for (int i = 1; i <= n; i ++){
ans = min(ans, f[i]);
}
for (int i = 1; i <= n; i ++){
if (f[i] == ans){
cout << i << " ";
}
}
cout << endl;
return 0;
}