首页 > 其他分享 >CodeForces 1508C Complete the MST

CodeForces 1508C Complete the MST

时间:2023-07-10 19:46:31浏览次数:45  
标签:typedef int ll MST CodeForces long fa 补图 1508C

洛谷传送门

AtCoder 传送门

比较需要观察的题。

设 \(v\) 为所有边权异或和。直觉是设一条未确定权值的边边权为 \(v\),其他的为 \(0\) 最优。证明大概就是讨论 MST 是否全部使用未确定权值的边。若全使用了,那么根据 \(\oplus w \le \sum w\) 可知 \(\min \sum w = \oplus w\),并且在 \(w\) 两两按位与均为 \(0\) 时取等;若没有全使用,可以把没使用的赋成 \(v\),其他全赋成 \(0\)。

发现若补图存在环,我们只要把一条构成环的边边权设为 \(v\) 即可,显然它会被环上其他边替代。补图存在环的一个必要条件是 \(m < \frac{n(n - 1)}{2} - n + 1\),因为补图边数 \(\ge n\)。这种情况下,我们先求出补图连通块,将他们作为边权为 \(0\) 的边在并查集上 merge 起来,再做一遍 Kruskal 即可。至于如何求补图连通块,这是个典题,可以考虑暴力 + 链表(并查集),具体见。这部分时间复杂度 \(O(m \log m + (n + m) \log n)\)。

若 \(m \ge \frac{n(n - 1)}{2} - n + 1\),此时补图边数 \(< n\),又因为 \(m\) 是 \(O(n^2)\) 级别,因此 \(n\) 是 \(O(\sqrt{m})\) 的。此时可以直接暴力枚举将补图的哪条边边权设为 \(v\),再做 Kruskal 即可。这部分时间复杂度 \(O(m \sqrt{m} \log n)\),实际用时不多。

code
// Problem: C. Complete the MST
// Contest: Codeforces - Codeforces Round 715 (Div. 1)
// URL: https://codeforces.com/problemset/problem/1508/C
// Memory Limit: 256 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<int, int> pii;

const int maxn = 200100;

ll n, m, fa[maxn];
struct E {
	ll u, v, d;
} G[maxn];

int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}

inline bool merge(int x, int y) {
	x = find(x);
	y = find(y);
	if (x != y) {
		fa[x] = y;
		return 1;
	} else {
		return 0;
	}
}

namespace Sub1 {
	void solve() {
		ll s = 0;
		for (int i = 1; i <= m; ++i) {
			s ^= G[i].d;
		}
		set<pii> st;
		for (int i = 1; i <= n; ++i) {
			for (int j = i + 1; j <= n; ++j) {
				st.insert(make_pair(i, j));
			}
		}
		for (int i = 1; i <= m; ++i) {
			int u = G[i].u, v = G[i].v;
			if (u > v) {
				swap(u, v);
			}
			st.erase(make_pair(u, v));
		}
		ll ans = 1e18;
		for (pii e : st) {
			for (int i = 1; i <= n; ++i) {
				fa[i] = i;
			}
			for (pii p : st) {
				if (e != p) {
					merge(p.fst, p.scd);
				}
			}
			ll res = 0;
			bool flag = 0;
			for (int i = 1; i <= m; ++i) {
				int u = G[i].u, v = G[i].v, d = G[i].d;
				if (s <= d && !flag) {
					flag = 1;
					if (merge(e.fst, e.scd)) {
						res += s;
					}
				}
				if (merge(u, v)) {
					res += d;
				}
			}
			ans = min(ans, res);
		}
		printf("%lld\n", ans);
	}
}

namespace Sub2 {
	bool vis[maxn];
	set<int> S[maxn];
	
	struct DSU {
		int fa[maxn];
		
		inline void init() {
			for (int i = 1; i <= n + 1; ++i) {
				fa[i] = i;
			}
		}
		
		int find(int x) {
			return fa[x] == x ? x : fa[x] = find(fa[x]);
		}
	} D;
	
	void dfs(int u) {
		vis[u] = 1;
		D.fa[u] = u + 1;
		for (int v = D.find(1); v <= n; v = D.find(v + 1)) {
			if (S[u].find(v) == S[u].end()) {
				merge(u, v);
				dfs(v);
			}
		}
	}
	
	void solve() {
		for (int i = 1; i <= n; ++i) {
			fa[i] = i;
		}
		D.init();
		for (int i = 1; i <= m; ++i) {
			int u = G[i].u, v = G[i].v;
			S[u].insert(v);
			S[v].insert(u);
		}
		for (int i = 1; i <= n; ++i) {
			if (!vis[i]) {
				dfs(i);
			}
		}
		ll ans = 0;
		for (int i = 1; i <= m; ++i) {
			int u = G[i].u, v = G[i].v, d = G[i].d;
			if (merge(u, v)) {
				ans += d;
			}
		}
		printf("%lld\n", ans);
	}
}

void solve() {
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= m; ++i) {
		scanf("%lld%lld%lld", &G[i].u, &G[i].v, &G[i].d);
	}
	sort(G + 1, G + m + 1, [&](E a, E b) {
		return a.d < b.d;
	});
	if (m >= n * (n - 1) / 2 - n + 1) {
		Sub1::solve();
	} else {
		Sub2::solve();
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:typedef,int,ll,MST,CodeForces,long,fa,补图,1508C
From: https://www.cnblogs.com/zltzlt-blog/p/17542120.html

相关文章

  • Camstar表格自定义写js,实现单元格合并。
     效果: ......
  • CodeForces 997C Sky Full of Stars
    洛谷传送门CF传送门考虑容斥,钦定\(i\)行\(j\)列放同一种颜色,其余任意。\(i=0\)或\(j=0\)的情况平凡,下面只考虑\(i,j\ne0\)的情况。答案为:\[\sum\limits_{i=1}^n\sum\limits_{j=1}^n(-1)^{i+j+1}\binom{n}{i}\binom{n}{j}3^{(n-i)(n-j)+1}......
  • Codeforces Round 883 (Div. 3)
    CodeforcesRound883(Div.3)A.RudolphandCuttheRope:题意:有一个糖果由n个绳子悬挂,告诉每一个绳子位于的高度和宽度,问至少间断几根才可以让candy回到groud。思路:统计有几个宽度小于高度的绳子即可voidsolve(){intn;intnum=0;cin>>n;for(inti=1;i......
  • Codeforces Round 875 (Div. 2)(D)
    CodeforcesRound875(Div.2)(D)D(思维)这个题意是给你两个数组,\(a\)和\(b\),我们需要找到这样的二元组\((i,j)\)满足\(a_i\timesa_j=b_i+b_j\),问一共有多少组满足以上条件的二元组题目还告诉我们数组里面的数字都是不大于\(n\)的,那么因为两个数相乘的范围一定是\(1-n\)的,那......
  • Codeforces Round 882 (Div. 2)
    Preface这场现场打的,顶着第二天一早起来军训硬打到一点这场题目都是JOJO确实好评,但刚开始的评测姬爆让人很难顶啊,因为这个B题挂了一发没法第一时间改导致这场罚时裂开了这场写完D还有快50min,然后看一眼榜E出的人很少但是F好多人过然后就去想F,由于军训生物钟的缘故当时好困好困......
  • Codeforces Round 882 (Div. 2) C. Vampiric Powers, anyone?
    由题目观察可得,a[m+1]=a[i]^...a[m],,结合异或的性质a^b^a=b,可得如果在末尾添加一个a[m+1],a[m+1]会和末尾几个抵消掉,求得i~k这一段的异或和,k<m,因此通过该操作实际上我就可以求得所有长度连续区间的异或和,求其最大值,n=1e5+10,如果暴力求解肯定会超时,我们观察发现a[i]的范围为0~2^8......
  • Codeforces Round 882 (Div. 2) A-D
    ATheManwhobecameaGod 假设sum为omigaabs(a[i]-a[i-1])1<=i<=n 只有设置断点的时候,假设设置在t和t-1之间thevalue才会减少abs(a[t]-a[t-1]) 所以把差距最大的几个地方分段就行了#include<bits/stdc++.h>usingnamespacestd;#definemaxn400100#defi......
  • Educational Codeforces Round 151 (Rated for Div. 2) D. Rating System
    贪心由题可得,对于k的选择一定是单调递增的,对于前面选定的k后面选的k必须大于之前选的才会发生新的变化,因此k的选择其实是一个单调栈,由前缀和组成我们要想最后的结果最大,则k值一定要尽可能的高,例如当选中i为k值时,如果从i后面某个原本的前缀和要大于选k之后所得到的前缀和的话,说明......
  • Educational Codeforces Round 151 (Rated for Div. 2) C. Strong Password
    题目翻译,给定t组数据,每组数据包含一个字符串s,两个长度为m的字符串l和r,要求判断是否存在一个长度为m的字符串res,满足l[i]<=res[i]<=r[i](i->0~m)且不是s的子序列贪心首先对于所有满足l<res<r的字符串,我们只需判断是否存在一个字符串不是子序列即可,那么我们让res成为子序列的可能......
  • 关于通过bat脚本-自动使用mstsc-远程桌面命令登录到远程windows主机的方法
    在Windows系统中,我们可以通过系统自带的mstsc远程桌面工具,登录到远端的windows服务器主机但是需要输入用户名和密码,回车、于是笔者想了一下,能不能创建一个bat文件,双击后,就会自动的传入用户名和密码进行登录经过查询和实验、还真有这样的办法(当然在正式的环境,不建议这样操作,因为......