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\n", 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]);}
希望我们都有一个光明的未来