ウイルス感染

リンク: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;
}

おすすめ

転載: blog.csdn.net/qq_45772483/article/details/112638939