P3623 [APIO2008]免费道路

P3623 [APIO2008]免费道路

WQS二分题解。(好像可以不用这个做法)

就是给每个点随一个权值,然后跑正常的WQS二分。

(l, r) 可以是浮点数。

时间 (O(n log^2n))

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <ctime>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;

ll N, M, K, fa[MAXN], vis[MAXN];
double ans = 1e99;

struct edge {
    ll x, y, c, id;
    double w;
    friend bool operator < (edge a, edge b) {return a.w == b.w ? a.c < b.c : a.w < b.w;}
} E[MAXN];

bool cmp(edge, edge);
ll check(double);
ll find_(ll);

int main() {
	srand(time(0));
    scanf("%lld%lld%lld", &N, &M, &K);
    for (ll i = 1; i <= M; i++) {
        scanf("%lld%lld%lld", &E[i].x, &E[i].y, &E[i].c);
        E[i].w = rand() % M; E[i].id = i;
    }
    double l = -1e8, r = 1e8;
    while (r - l >= 1e-5) {
        double mid = (l + r) / 2.0;
        ll num = check(mid);
        if (num > K) l = mid + 1;
        else if (num == K) {l = mid + 1, ans = mid; break;} 
        else r = mid - 1;
    }
    if (ans == 1e99) {
    	puts("no solution");
		return 0;
	}
	sort(E+1, E+M+1, cmp);
    for (ll i = 1; i <= M; i++)
        if (vis[i])
            printf("%lld %lld %lld
", E[i].x, E[i].y, E[i].c);
    return 0;
}

bool cmp(edge a, edge b) {return a.id < b.id;}

ll check(double now) {
    for (ll i = 1; i <= N; i++) fa[i] = i;
    for (ll i = 1; i <= M; i++) {
		if (!E[i].c) E[i].w += now;
		vis[i] = 0;
	}
    sort(E+1, E+M+1);
    ll ret = 0;
    for (ll i = 1, cnt = 1; cnt < N && i <= M; i++) {
        ll fx = find_(E[i].x), fy = find_(E[i].y);
        if (fx != fy) {
            cnt++;
            fa[fx] = fy;
            ret += (E[i].c == 0 ? 1 : 0);
            vis[E[i].id] = 1;
        }
    }
    for (ll i = 1; i <= M; i++) if (!E[i].c) E[i].w -= now;
    return ret;
}

ll find_(ll x) {return fa[x] == x ? x : fa[x] = find_(fa[x]);}
原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/13904550.html