BZOJ3624: [Apio2008] free road (minimum spanning tree)

Posted by tonbah on Mon, 30 Dec 2019 16:45:36 +0100

meaning of the title

Title Link

Sol

The first answer must be a tree

There are some 0 sides on this tree that must be selected. Let's find them first. If the number $\ geqslant k $, it is obvious that there is no solution

Then consider adding the edge of 0 to it, and judge whether it can be added to k

The specific methods are as follows:

First, let 1 make a spanning tree before it, and the 0 side added must be selected

Let 0 side make a spanning tree in front of us. At this time, we don't need to consider whether we can generate a tree at last, just whether we can add k-pieces

My idea: first of all, the 0 sides that must be selected must be counted, and then all the remaining 0 sides will be added at one time. Obviously, there will be many useless ones. If the number of added sides $< K $, there will be no solution,

Otherwise, consider deleting some 0 sides. LCT maintains the number of 0 sides on each ring after forming a ring. If the number of 0 sides on the ring $> 0 $, subtract one, and add the 1 side. Otherwise, it will not be added. If the total number of 0 sides is k,

Add the remaining edge directly, and finally judge whether a tree can be formed. Otherwise, the number of zero sides is more than k, and prove that there is no solution.

It should be right, but I won't write it even if I'm killed.....

 

#include<cstdio>
#include<algorithm>
#define LL long long 
using namespace std;
const int MAXN = 3 * 1e5 + 10, INF = 1e9 +10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, M, K, num, mt, fa[MAXN];
struct Edge {
    int u, v, w, f;
    bool operator < (const Edge &rhs) const {return w > rhs.w;}
}E[MAXN];
void AddEdge(int x, int y, int z) {E[++num] = (Edge) {x, y, z};}
int comp(const Edge &a, const Edge &b) {return a.w < b.w;}
int find(int x) {return fa[x] == x ? fa[x] : (fa[x] = find(fa[x]));}
int calc() {
    int ans = 0;
    for(int i = 1; i <= num; i++) if(E[i].f) ans++;
    return ans;
}
int Kruskal(int opt) {
    if(opt == 1) sort(E + 1, E + num + 1);
    else sort(E + 1, E + num + 1, comp);
    for(int i = 1; i <= N; i++) fa[i] = i;
    int cnt = 0;
    if(opt == 2) 
        for(int i = 1; i <= num; i++) 
            if(E[i].f) fa[find(E[i].u)] = find(E[i].v), cnt++;
    for(int i = 1; i <= num; i++) {
        int x = E[i].u, y = E[i].v, w = E[i].w;
        int fx = find(x), fy = find(y);
        if(fx == fy) continue;
        if(opt == 1) {
            if(w == 0) E[i].f = 1;
            if((++cnt) == N - 1) return calc();
        } else if(opt == 2) {
            cnt++; E[i].f = 1;
            if(cnt == K) return 1;
        } else if(opt == 3) {
            if(w == 0 && (!E[i].f)) continue;
            if((++cnt <= N - 1)) printf("%d %d %d\n", x, y, w);
        }
        fa[fx] = fy;
    }
    return 0;
}
int main() {
    N = read(); M = read(); K = read();
    for(int i = 1; i <= M; i++) {
        int x = read(), y = read(), z = read();
        AddEdge(x, y, z); //AddEdge(y, x, z);
    }
    if(Kruskal(1) > K) {puts("no solution"); return 0;}
    if(!Kruskal(2)) {puts("no soltion"); return 0;}
    Kruskal(3);
    return 0;
}

Topics: C++