Loading

CF125E MST Company 题解

代码写的可能比较繁琐,请见谅。

思路

首先考虑 \(\text{wqs}\) 二分。

对所有连向 \(s\) 的边进行定量偏移。

即所有连向 \(s\) 的边的边权 \(q\) 加上二分的定量 \(\Delta\)

就可以将这一个问题变成一个可行性问题。

可能比较困难的一点就是当 \(\Delta\) 一定时,可能拥有不同的 \(k\) 的方案。

本篇主要讲述如何构造一个正确的方案。

首先判断一个无解的情况。

  1. \(s\) 的出边不足 \(k\)
  2. 原图不联通。
  3. 使原图联通 \(s\) 必须连的出边超过 \(k\)

除去上面三种情况,所有的情况必然会有一个解。

考虑对于一个偏移量如何构造出这样的一个解。

首先可以构造出一组 \(s\) 出边最少的解。

考虑在此基础上将其增加至 \(k\) 条出边。

对于相同权值的边,我们先将原方案中所连的出边进行连接。

然后如果不足 \(k\) 条出边,再去考虑相同权值下的其他出边。

最后再去考虑相同权值下的其他边。

可以发现,原方案中所连的出边一定还会在新方案中被连。

这是由于虽然我们增加了一些边,但对于原方案中所连的出边所更改的联通性是不会进行改变的(不然就会出现在原方案中)。

容易发现这样也一定不会比原方案更劣(原理大致与朴素的 \(\text{kruskal}\) 差不多),并且一定有解。

这样就有了一个大致的算法流程。

具体可以看代码。

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1000010;

int n, m, k, s, kl, top, fa[N], vis[N], ans[N];

class Graph
{
    public:
        int cnt;
        struct edge { int to, nxt, val, id; }e[N];
        inline edge &operator[](int tmp) { return e[tmp]; }
        inline void init(int x) { for (int i = 1;i <= cnt;i++) e[i].val += x; }
        inline void add(int x , int y , int z , int i) { e[++cnt] = {x, y, z, i}; }
        inline void mySort() { sort(e + 1, e + cnt + 1, [](edge a, edge b) { return a.val < b.val; }); }
} graBlack, graWhite;

inline int read()
{
    int asd = 0 , qwe = 1; char zxc;
    while(!isdigit(zxc = getchar())) if(zxc == '-') qwe = -1;
    while(isdigit(zxc)) asd = asd * 10 + zxc - '0' , zxc = getchar();
    return asd * qwe;
}

inline bool check(int x , int y) { return (x == s || y == s); }
inline int gf(int x) { return (fa[x] == x ? fa[x] : fa[x] = gf(fa[x])); }

inline bool merge(int x , int y) 
{ 
    int fx = gf(x), fy = gf(y); 
    if(fx == fy) return 0;
    fa[fx] = fy; return 1;
}

inline int kruskal()
{
    int num = 0; top = 0;
    iota(fa + 1, fa + n + 1, 1);
    for (int i = 1, l = 1, r = 1; i <= m; i++)
        if (l <= graBlack.cnt && graBlack[l].val < graWhite[r].val)
            merge(graBlack[l].to, graBlack[l].nxt) , l++;
        else num += merge(graWhite[r].to, graWhite[r].nxt), r++;
    return num;
}

inline void checkSol()
{
    int cnt = 0 , sum = 0;
    for (int i = 1; i <= graBlack.cnt;i++)
        cnt += merge(graBlack[i].to, graBlack[i].nxt);
    for (int i = 1; i <= graWhite.cnt; i++)
        if(merge(graWhite[i].to, graWhite[i].nxt)) cnt++, sum++;
    if (cnt != n - 1 || sum > k || graWhite.cnt < k)
        puts("-1"), exit(0);
}

inline void makeSol(int mid)
{
    graWhite.init(mid), top = 0;
    iota(fa + 1, fa + n + 1, 1);
    int sum = 0, l = 1, r = 1, i, j;
    for (i = 1; i <= m; i++)
        if (l <= graBlack.cnt && graBlack[l].val <= graWhite[r].val)
            merge(graBlack[l].to, graBlack[l].nxt), l++;
        else 
        {
            if (merge(graWhite[r].to, graWhite[r].nxt))
                vis[r] = 1, k--;
            r++;
        };
    l--, r--, top = 0;
    iota(fa + 1, fa + n + 1, 1);
    for (i = 1, j = 1; i <= graBlack.cnt;i++)
    {
        while(j <= r && graWhite[j].val <= graBlack[i].val)
        {
            int ls = j, rs = j;
            int x = graWhite[j].val;
            while(rs < r && graWhite[rs + 1].val == x)
                rs++;
            for (int j = ls; j <= rs;j++)
                if (vis[j] && merge(graWhite[j].to, graWhite[j].nxt))
                    sum += graWhite[j].val, ans[++top] = graWhite[j].id;
            for (int j = ls; j <= rs && k; j++)
                if(merge(graWhite[j].to, graWhite[j].nxt))
                    sum += graWhite[j].val, k--, ans[++top] = graWhite[j].id;
            j = rs + 1;
        }
        if(merge(graBlack[i].to, graBlack[i].nxt))
            sum += graBlack[i].val, ans[++top] = graBlack[i].id;
    }
    while (j <= r)
    {
        int ls = j, rs = j;
        int x = graWhite[j].val;
        while (rs < r && graWhite[rs + 1].val == x)
            rs++;
        for (int j = ls; j <= rs; j++)
            if (vis[j] && merge(graWhite[j].to, graWhite[j].nxt))
                sum += graWhite[j].val, ans[++top] = graWhite[j].id;
        for (int j = ls; j <= rs && k; j++)
            if (merge(graWhite[j].to, graWhite[j].nxt))
                sum += graWhite[j].val, k--, ans[++top] = graWhite[j].id;
        j = rs + 1;
    }
    cout << n - 1 << endl;
    for (i = 1; i <= top;i++)
        cout << ans[i] << " ";
    cout << endl;
}

inline void wqsDichotomous()
{
    int l = -1e9, r = 1e9;
    graBlack.mySort(), graWhite.mySort();
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        graWhite.init(mid);
        int x = kruskal();
        graWhite.init(-mid);
        if (x > k) l = mid + 1;
        if (x < k) r = mid - 1;
        if (x == k) break;
    }
    makeSol((l + r) >> 1);
}

signed main()
{
    n = read(), m = read(), s = 1, kl = k = read();
    iota(fa + 1, fa + n + 1, 1);
    for (int i = 1; i <= m; i++)
    {
        int x = read(), y = read(), z = read();
        if (check(x, y)) graWhite.add(x, y, z, i);
        else graBlack.add(x, y, z, i);
    }
    checkSol(), wqsDichotomous();
    return 0;
}
posted @ 2022-11-02 21:25  JiaY19  阅读(45)  评论(0编辑  收藏  举报