cf444E. DZY Loves Planting(並查集)

自為風月馬前卒發表於2018-10-28

題意

題目連結

Sol

神仙題啊Orzzzzzz

考場上的時候直接把樹扔了對著式子想,想1h都沒得到啥有用的結論。

然後cf正解居然是網路流??出給NOIP模擬賽T1???¥%……&((……%&((

說一下非網路流解法吧。

首先題目中給出的(g(i, p_i))我們可以認為是對於每個節點(i),分配一個節點(p_i),同時還有數量(x_i)的限制

同時題目中要求的是最小值最大,不難想到二分答案。但其實只要把邊從小到大排序,依次考慮每條邊能否成為答案就行了

用並查集維護節點之間的聯通性,對於一條邊來說,如果這條邊可以成為答案,那麼對於當前已經合併的每個點,我們都需要給它分配一個未被合併的點(注意這裡邊權是已經排好序的)

維護(siz[x])表示(x)節點的連通塊的大小,(sum = sum_{i = 1}^n x_i), (f[x])表示已經合併的節點的(x_i)之和(也就是不能使用的點)

那麼一條邊可以被合併的條件為(siz[x] <= sum – f[x])

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < `0` || c > `9`) {if(c == `-`) f = -1; c = getchar();}
    while(c >= `0` && c <= `9`) x = x * 10 + c - `0`, c = getchar();
    return x * f;
}
int N, fa[MAXN], x[MAXN], siz[MAXN], sum;
struct Edge {
    int u, v, w;
    bool operator < (const Edge &rhs) const {
        return w < rhs.w;
    }
}E[MAXN];
int find(int x) {
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}
int main() {
    N = read();
    for(int i = 1; i <= N; i++) fa[i] = i, siz[i] = 1;
    for(int i = 1; i <= N - 1; i++) E[i].u = read(), E[i].v = read(), E[i].w = read();
    sort(E + 1, E + N);
    for(int i = 1; i <= N; i++) x[i] = read(), sum += x[i];
    for(int i = 1; i <= N - 1; i++) {
        int fx = find(E[i].u), fy = find(E[i].v);
        if(fx == fy) continue;
        fa[fy] = fx; siz[fx] += siz[fy]; x[fx] += x[fy];
        if(siz[fx] > sum - x[fx]) {printf("%d
", E[i].w); return 0;}
    }
    printf("%d
", E[N - 1].w);
    return 0;
}

相關文章