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; }
既然选择了远方,就要风雨兼程~
posted on 2017-03-05 23:57 stupid_one 阅读(184) 评论(0) 编辑 收藏 举报