Codeforces 1281E
題意:一棵$2n$個點的樹讓你分配$n$對居民在點上求每對居民之間路徑和的最小值和最大值
思路:考慮一條邊$(u, v)$
1.若要使答案盡可能大,那么這條邊應該取到盡可能多次。顯然,如果$u, v$的子樹大小分別表示成$sz_u, sz_v$,那么這條邊最多被覆蓋$min(sz_u, sz_v)$次,算出每條邊最多被取到的次數再乘以邊長就是最大值了。
2.若要使答案盡可能小,那么我們應該讓每條邊最多取到$1$次,我們考慮$sz_u, sz_v$的奇偶性,發現他們是同奇偶性的。如果都是偶數,那么這條邊就可以不取,因為兩個子樹可以內部完成,否則這條邊必須取到,因為假設兩個內部盡可能多的完成了,依舊會分別至少剩下$1$個點沒分配,所以這條邊必定被覆蓋。
#include <bits/stdc++.h>
#define DBG(x) cerr << #x << " = " << x << endl
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int n, head[N], tot, sz[N]; ll mx, mn;
struct Enode {
int to, nxt, w;
} edge[N * 2];
void addedge(int u, int v, int w) {
edge[tot].to = v;
edge[tot].w = w;
edge[tot].nxt = head[u];
head[u] = tot++;
}
void dfs(int u, int f) {
sz[u] = 1;
for(int i = head[u]; i != -1; i = edge[i].nxt) {
int v = edge[i].to, w = edge[i].w;
if(v == f) continue;
dfs(v, u);
if(sz[v] & 1) mn += w;
mx += (ll)w * min(sz[v], n - sz[v]);
sz[u] += sz[v];
}
}
void solve() {
scanf("%d", &n);
for(int i = 1; i <= 2 * n; i++) head[i] = -1, sz[i] = 0; tot = mn = mx = 0;
n = 2 * n;
for(int i = 1, u, v, w; i < n; i++) {
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
addedge(v, u, w);
}
dfs(1, -1);
printf("%lld %lld\n", mn, mx);
}
int main() {
int cs; for(scanf("%d", &cs); cs--; solve());
}

浙公網安備 33010602011771號