1. 程式人生 > >[BZOJ 2654] tree

[BZOJ 2654] tree

tree printf += pla kruskal nlogn name c++ main

[題目鏈接]

https://www.lydsy.com/JudgeOnline/problem.php?id=2654

[算法]

給白色邊都加上一個值,會使得最小生成樹上的白邊數量減少,不妨二分給白色邊加上的值 , 檢驗答案時用Kruskal求最小生成樹即可

時間復雜度 : O(NlogN)

[代碼]

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define MAXM 200010

struct edge
{
    int u , v , w , type;
} e[MAXN];

int tot , n , m , value , ans; int fa[MAXN]; template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); } template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == -) f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - 0; x *= f; } inline int get_root(int x) { if (fa[x] == x) return x; return fa[x] = get_root(fa[x]); } inline bool cmp(edge a , edge b) { return a.w == b.w ? a.type < b.type : a.w < b.w; } inline
bool check(int mid) { int cnt = 0; tot = 0; for (int i = 1; i <= n; i++) fa[i] = i; for (int i = 1; i <= m; i++) if (!e[i].type) e[i].w += mid; sort(e + 1 , e + m + 1 , cmp); for (int i = 1; i <= m; i++) { int su = get_root(e[i].u) , sv = get_root(e[i].v); if (su != sv) { fa[su] = sv; tot += e[i].w; if (!e[i].type) ++cnt; } } for (int i = 1; i <= m; i++) if (!e[i].type) e[i].w -= mid; return cnt >= value; } int main() { read(n); read(m); read(value); for (int i = 1; i <= m; i++) { read(e[i].u); read(e[i].v); read(e[i].w); ++e[i].u; ++e[i].v; read(e[i].type); } int l = -105 , r = 105 , ans = 0; while (l <= r) { int mid = (l + r) / 2; if (check(mid)) { ans = tot - value * mid; l = mid + 1; } else r = mid - 1; } printf("%d\n" , ans); return 0; }

[BZOJ 2654] tree