bzoj3624 [Apio2008]免费道路
Description
Input
OutPut
Sample Input
5 7 2
1 3 0
4 5 1
3 2 0
5 3 1
4 3 0
1 2 1
4 2 1
Sample Output
3 2 0
4 3 0
5 3 1
1 2 1
Solution
失踪人口回归。
题目大意:求图一棵生成树,使得这棵树里恰好有 \(k\) 条特殊边。
两遍 \(kruskal\) ,第一遍优先加入非特殊边,预处理出有哪些边是非选不可的。第二遍先加入 \(k\) 条特殊边,再加入非特殊边。判断 \(no\) \(solution\)时细节较多,详见代码。
#include<bits/stdc++.h>
using namespace std;
#define N 200001
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define drp(i, a, b) for (int i = a; i >= b; i--)
#define No { puts("no solution"); return 0; }
inline int read() {
int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
}
inline void write(int x) {
if (!x) { putchar('0'); return; } if (x < 0) putchar('-'), x = -x;
char buf[30] = ""; int top = 0; while (x) buf[++top] = x % 10 + '0', x /= 10; while (top) putchar(buf[top--]);
}
int n, m, K;
struct edgeType {
int u, v, w; bool chos;
void outPut() { if (!chos) return; write(u), putchar(' '), write(v), putchar(' '), write(w), puts(""); }
}eg[N];
bool cmp(const edgeType& a, const edgeType& b) { return a.w > b.w; }
int fa[20001];
int find(int x) { return fa[x] ? fa[x] = find(fa[x]) : x; }
int main() {
n = read(), m = read(), K = read();
rep(i, 1, m) eg[i].u = read(), eg[i].v = read(), eg[i].w = read(); sort(eg + 1, eg + 1 + m, cmp);
int spCnt = 0;
rep(i, 1, m) {
int x = find(eg[i].u), y = find(eg[i].v); if (!(x ^ y)) continue;
fa[x] = y; if (!eg[i].w) eg[i].chos = 1, spCnt++;
}
if (spCnt > K) No;
memset(fa, 0, sizeof fa); int cnt = 0; spCnt = 0;
rep(i, 1, m) if (eg[i].chos) { fa[find(eg[i].u)] = find(eg[i].v); cnt++; spCnt++; continue; }
drp(i, m, 1) {
if (cnt == n - 1) break; if (eg[i].w && spCnt != K) No;
int x = find(eg[i].u), y = find(eg[i].v); if (!(x ^ y) || eg[i].chos) continue;
if (!eg[i].w && spCnt < K) fa[x] = y, eg[i].chos = 1, spCnt++, cnt++;
else if (eg[i].w) fa[x] = y, eg[i].chos = 1, cnt++;
}
if (cnt ^ (n - 1)) No;
rep(i, 1, m) eg[i].outPut();
return 0;
}