• [CF1108F]MST Unification


    题目大意:给一张$n(nleqslant2 imes10^5)$个点$m(mleqslant2 imes10^5)$条边的无向带权图,定义一次操作为把一条边边权加一,求要使最小生成树唯一的最少操作数。

    题解:先求一个最小生成树,对于任意一条不在最小生成树上的边,只有当它连上后形成的环上有和它边权相同的边时,最小生成树才是不唯一的,这是就要把这条边边权加一,并且,相同的那一条边一定是这个环上边权最大的边。所以可以用树上倍增求这条边,然后比较一下就行了。

    卡点:树上倍增多处写错

    C++ Code:

    #include <algorithm>
    #include <cstdio>
    #define maxn 200010
    
    int head[maxn], cnt;
    struct Edge {
    	int to, nxt, w;
    	inline bool operator < (const Edge &rhs) const {
    		return w < rhs.w;
    	}
    } e[maxn << 1], E[maxn];
    inline void addedge(int a, int b, int c) {
    	e[++cnt] = (Edge) { b, head[a], c }; head[a] = cnt;
    	e[++cnt] = (Edge) { a, head[b], c }; head[b] = cnt;
    }
    
    int n, m;
    int f[maxn];
    int find(int x) { return x == f[x] ? x : (f[x] = find(f[x])); }
    bool used[maxn];
    
    #define M 17
    int fa[maxn][M + 1], Mx[maxn][M + 1], dep[maxn];
    void dfs(int u) {
    	for (int i = 1; i <= M; ++i) {
    		fa[u][i] = fa[fa[u][i - 1]][i - 1];
    		Mx[u][i] = std::max(Mx[u][i - 1], Mx[fa[u][i - 1]][i - 1]);
    	}
    	for (int i = head[u]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if (v != *fa[u]) {
    			*fa[v] = u;
    			*Mx[v] = e[i].w;
    			dep[v] = dep[u] + 1;
    			dfs(v);
    		}
    	}
    }
    #define chkmin(x, i) res = std::max(res, Mx[x][i]), x = fa[x][i]
    inline int calc(int x, int y) {
    	int res = 0;
    	if (dep[x] < dep[y]) std::swap(x, y);
    	for (int i = dep[x] - dep[y]; i; i &= i - 1) chkmin(x, __builtin_ctz(i));
    	if (x == y) return res;
    	for (int i = M; ~i; --i) if (fa[x][i] != fa[y][i]) chkmin(x, i), chkmin(y, i);
    	return std::max(res, std::max(*Mx[x], *Mx[y]));
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	for (int i = 0; i < m; ++i) scanf("%d%d%d", &E[i].to, &E[i].nxt, &E[i].w);
    	std::sort(E, E + m);
    	for (int i = 1; i <= n; ++i) f[i] = i;
    	{
    		int num = n - 1;
    		for (int i = 0; i < m && num; ++i) {
    			int u = E[i].to, v = E[i].nxt, x = find(u), y = find(v);
    			if (x != y) {
    				f[x] = y;
    				--num;
    				used[i] = true;
    				addedge(u, v, E[i].w);
    			}
    		}
    	}
    	dfs(1);
    	int ans = 0;
    	for (int i = 0; i < m; ++i) if (!used[i]) ans += E[i].w == calc(E[i].to, E[i].nxt);
    	printf("%d
    ", ans);
    	return 0;
    }
    

      

  • 相关阅读:
    多线程设计的要素—任务线程确定
    https://www.neroxie.com/2019/01/22/深入理解GCD之dispatch-group/
    性能、指标、监控、数据大盘
    iOS PhotoKit 笔记
    多线程的核心问题是控制共享变量的无序访问(读写)
    objective-c arc -对象、变量、变量修饰符、赋值
    大幅降低存储成本,Elasticsearch可搜索快照是如何办到的?
    压测利器:TarsBenchmark正确打开方式
    跨国合作:Serverless Components 在腾讯云的落地和实践
    前端视角谈物联网三部曲:连接智能、交互智能、数据智能
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/10335626.html
Copyright © 2020-2023  润新知