首页 > 代码库 > B. Connecting Universities DFS,无向树

B. Connecting Universities DFS,无向树

http://codeforces.com/problemset/problem/700/B

题意是,在一颗树中,有k个大学,要求两两匹配,他们之间的距离作为贡献,使得距离总和最大。

一开始的时候无从下手,一路在想某一个点应该和哪一个点去匹配。但是这样是错误的思路。

正解是观察边的贡献,如果某两个学校连接了,那么肯定有一条路径的,这条路径会经过很多的边,我们把经过某条边的次数统计出来。那么答案就是这棵树的边的权值和。

那怎么算一条边的贡献呢。

贪心地去想,

某一条边,把整颗树分成了两部分,那么第一部分的学校肯定是连去第二部分的学校,这样的距离比较大。

那么就是有min(partI, k - partI)的贡献。dfs下去就好。脑洞好大。。不是我的题目

技术分享
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 200000 + 20;
bool is[maxn];
struct Edge {
    int u, v, tonext;
}e[maxn * 2];
int num, first[maxn];
void add(int u, int v) {
    ++num;
    e[num].u = u, e[num].v = v, e[num].tonext = first[u];
    first[u] = num;
}
LL ans, son[maxn];
int n, k;
void dfs(int cur, int fa) {
    son[cur] = is[cur];
    for (int i = first[cur]; i; i = e[i].tonext) {
        int v = e[i].v;
        if (v == fa) continue;
        dfs(v, cur);
        ans += min(k - son[v], son[v]);
        son[cur] += son[v];
    }
}
void work() {
    cin >> n >> k;
    k <<= 1;
    for (int i = 1; i <= k; ++i) {
        int x;
        cin >> x;
        is[x] = true;
    }
    for (int i = 1; i <= n - 1; ++i) {
        int u, v;
        cin >> u >> v;
        add(u, v);
        add(v, u);
    }
    dfs(1, 0);
    cout << ans << endl;
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}
View Code

 

B. Connecting Universities DFS,无向树