CF1508C Complete the MST

CF1508C Complete the MST

来做一道 MST 题。

观察题目感受性质,发现要求所有边异或和为 \(0\) 这一条件很弱,不妨先不管这个约束直接做。显然令所有非关键边边权为 \(0\),可以先求补图的连通块,然后做 Kruskal。

现在考虑加上这个限制。设原图边权异或和为 \(x\),那么显然只令一条边边权为 \(x\) 是不劣的。

不难发现有很多情况下依然可以假设所有非关键边边权为 \(0\),具体来说就是非关键边形成环,即边数与连通块数之和大于点数的情况。

剩下的情况只需考虑能否用关键边替换 \(x\)。发现原图中可能存在环,环上较大的边是不可能称为 MST 的一部分的,剩下的边都可以尝试和 \(x\) 替换,取它们的最小值即可。

#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>
#define pii pair<int, int>
#define mp make_pair
#define fir first
#define sec second
 
using namespace std;
 
namespace IO {
  #define isdigit(x) (x >= '0' && x <= '9')
  template<typename T>
  inline void read(T &x) {
    x = 0; char ch = getchar(); int f = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    if(f) x = -x;
  }
  template<typename T>
  inline void write(T x) {
    if(x < 0) putchar('-'), x = -x;
    if(x > 9) write(x / 10);
    putchar(x % 10 + '0');
  }
  #undef isdigit
}
using namespace IO;
 
const int N = 2e5 + 10;
 
int n, m;
int d[N];
struct Edge {
  int u, v, w;
}e[N];
vector<int> G[N];
 
map<pii, int> vis;
 
int cnt = 0;
int dsu[N], sz[N];
int find(int x) {return x == dsu[x] ? x : (dsu[x] = find(dsu[x]));}
inline void merge(int x, int y) {
  x = find(x), y = find(y);
  if(x == y) return;
  if(sz[x] > sz[y]) swap(x, y);
  dsu[x] = y;
}
 
void getBlock() {
  for(int i = 1; i <= n; ++i)
    dsu[i] = i;
 
  int x = 1;
  for(int i = 2; i <= n; ++i)
    if(d[i] < d[x]) x = i;
 
  static bool tag[N];
  memset(tag, 0, sizeof tag);
  tag[x] = 1;
  for(int v : G[x]) tag[v] = 1;
  for(int i = 1; i <= n; ++i)
    if(!tag[i]) merge(x, i), vis[mp(x, i)] = vis[mp(i, x)] = 1;
 
  int id = find(x);
  for(int i = 1; i <= n; ++i) {
    if(find(i) == id) continue;
    memset(tag, 0, sizeof tag);
    for(int v : G[i]) 
      tag[v] = 1;
    tag[i] = 1;
    for(int j = 1; j <= n; ++j)
      if(!tag[j] && !vis[mp(i, j)]) merge(i, j), vis[mp(i, j)] = vis[mp(j, i)] = 1;
  }
}
 
int x, sum;
 
int main() {
  read(n), read(m);
  for(int i = 1, u, v, w; i <= m; ++i) {
    read(u), read(v), read(w);
    e[i].u = u, e[i].v = v, e[i].w = w;
    G[u].emplace_back(v), G[v].emplace_back(u);
    ++d[u], ++d[v];
    x ^= w;
  }
 
  getBlock();
  for(int i = 1; i <= n; ++i) 
    if(dsu[i] == i) ++cnt; 
 
  sort(e + 1, e + m + 1, [](Edge x, Edge y) {return x.w < y.w;});
 
  static int tag[N];
  memset(tag, 0, sizeof tag);
  for(int i = 1; i <= m; ++i) {
    int u = e[i].u, v = e[i].v, w = e[i].w;
    if(find(u) != find(v)) {
      tag[i] = 1;
      sum += w;
      merge(u, v);
    }
  }
  if(cnt + 1ll * n * (n - 1) / 2 - m > n) {
    printf("%d\n",sum);
    return 0;
  }
 
  for(int i = 1; i <= n; ++i) dsu[i] = i;
  for(int i = 1; i <= m; ++i) {
    int u = e[i].u, v = e[i].v, w = e[i].w;
    if(find(u) == find(v)) continue;
    merge(u, v);
    if(!tag[i]) {x = min(x, w); break;}
  }
  printf("%d\n",sum + x);
  return 0;
}
posted @ 2023-02-03 10:36  DCH233  阅读(18)  评论(0编辑  收藏  举报