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;
}