1. 程式人生 > 其它 >luogu P5631 最小mex生成樹

luogu P5631 最小mex生成樹

https://www.luogu.com.cn/problem/P5631

類似SUM那題
挖掉某一塊後看是否還是能構成生成樹
考慮分治,用按秩合併並查集來維護聯通性

code:

#include<bits/stdc++.h>
#define N 2000050
using namespace std;
struct E {
    int u, v, c;
} e[N];
int cmp(E x, E y) {
    return x.c < y.c;
}
int fa[N], siz[N], n, m;
int get(int x) {
    return fa[x] == x ? x : get(fa[x]);
}
int merge(int x, int y) {
    x = get(x), y = get(y);
    if(x == y) return 0;
    if(siz[x] > siz[y]) swap(x, y);
    fa[x] = y, siz[y] += siz[x];
    return x;
}
void del(int x) {
    siz[fa[x]] -= siz[x];
    fa[x] = x;
}
void cdq(int l, int r, int L, int R) {
    if(l == r) {   
        //if(l == e[m].c + 1) printf("%d ", siz[get(1)]);
        if(siz[get(1)] == n) {
            printf("%d", l);
            exit(0);
        }
        return ;
    }

    vector<int> sta;
    int mid = (l + r) >> 1, pos = R;
    while(pos >= L && e[pos].c > mid) sta.push_back(merge(e[pos].u, e[pos].v)), pos --;
     cdq(l, mid, L, pos);
    while(sta.size()) del(sta.back()), sta.pop_back(); sta.clear();

    for(int i = L; i <= pos; i ++) sta.push_back(merge(e[i].u, e[i].v));
    cdq(mid + 1, r, pos + 1, R);
    while(sta.size()) del(sta.back()), sta.pop_back(); sta.clear();
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i ++) scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].c);
    for(int i = 1; i <= n; i ++) fa[i] = i, siz[i] = 1;
    sort(e + 1, e + 1 + m, cmp);
    cdq(0, e[m].c + 1, 1, m);    
    return 0;
}