zoukankan      html  css  js  c++  java
  • BZOJ1977 [BJOI2010]次小生成树

    题目蓝链

    Solution

    考虑首先建出一棵最小生成树,然后再枚举所有其他的边。然后直接查询这条边对应在树上的两点之间的链上最大值和次大值,因为要保证严格次小。然后用查询的值更新一下答案

    维护一条链上的最大值和次大值,直接倍增就行了

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define squ(x) ((LL)(x) * (x))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    
    typedef long long LL;
    typedef pair<int, int> pii;
    
    inline int read() {
    	int sum = 0, fg = 1; char c = getchar();
    	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
    	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
    	return fg * sum;
    }
    
    const int maxn = 1e5 + 10;
    const int maxm = 3e5 + 10;
    const LL inf = 0x3f3f3f3f3f3f3f3f;
    
    int n, m;
    bool b[maxm];
    struct edge {
    	int x, y, z;
    	bool operator < (const edge &t) const { return z < t.z; }
    }e[maxm];
    
    vector<pii> g[maxn];
    
    namespace MST {
    
    	int fa[maxn];
    	int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
    
    	LL kruskal() {
    		LL res = 0;
    		sort(e + 1, e + m + 1);
    		for (int i = 1; i <= n; i++) fa[i] = i;
    		for (int i = 1; i <= m; i++) {
    			int x = find(e[i].x), y = find(e[i].y);
    			if (x == y) continue;
    			g[e[i].x].push_back((pii){e[i].y, e[i].z});
    			g[e[i].y].push_back((pii){e[i].x, e[i].z});
    			fa[x] = y; res += e[i].z; b[i] = 1;
    		}
    		return res;
    	}
    
    }
    
    struct node {
    	int x, y;
    	node(int _x = -1, int _y = -1): x(_x), y(_y) { }
    }Max[maxn][17];
    
    bool cmp(int x, int y) { return x > y; }
    int t[5];
    node merge(const node &a, const node &b) {
    	t[0] = a.x, t[1] = a.y;
    	t[4] = b.x, t[3] = b.y;
    	sort(t, t + 5, cmp);
    	unique(t, t + 5);
    	return (node){t[0], t[1]};
    }
    
    int fa[maxn][17], d[maxn];
    
    void dfs(int now, int f) {
    	fa[now][0] = f, d[now] = d[f] + 1;
    	for (int i = 1; i <= 16; i++) {
    		fa[now][i] = fa[fa[now][i - 1]][i - 1];
    		Max[now][i] = merge(Max[now][i - 1], Max[fa[now][i - 1]][i - 1]);
    	}
    	for (int i = 0; i < g[now].size(); i++) {
    		int son = g[now][i].first, ds = g[now][i].second;
    		if (son == f) continue;
    		Max[son][0] = (node){ds, -1};
    		dfs(son, now);
    	}
    }
    
    node find(int x, int y) {
    	if (d[x] < d[y]) swap(x, y);
    	node res = (node){-1, -1};
    	for (int i = 16; ~i; i--)
    		if (d[fa[x][i]] >= d[y]) res = merge(res, Max[x][i]), x = fa[x][i];
    	if (x == y) return res;
    	for (int i = 16; ~i; i--)
    		if (fa[x][i] != fa[y][i]) {
    			res = merge(res, Max[x][i]);
    			res = merge(res, Max[y][i]);
    			x = fa[x][i], y = fa[y][i];
    		}
    	res = merge(res, Max[x][0]);
    	res = merge(res, Max[y][0]);
    	return res;
    }
    
    int main() {
    #ifdef xunzhen
    	freopen("tree.in", "r", stdin);
    	freopen("tree.out", "w", stdout);
    #endif
    
    	n = read(); m = read();
    	for (int i = 1; i <= m; i++) {
    		int x = read(), y = read(), z = read();
    		e[i] = (edge){x, y, z};
    	}
    
    	LL sum = MST :: kruskal(), ans = inf;
    
    	t[4] = -1, dfs(1, 0);
    
    	for (int i = 1; i <= m; i++)
    		if (!b[i]) {
    			node res = find(e[i].x, e[i].y);
    			if (e[i].z > res.x) ans = min(ans, sum + e[i].z - res.x);
    			else if (e[i].z > res.y) ans = min(ans, sum + e[i].z - res.y);
    		}
    
    	printf("%lld
    ", ans);
    
    	return 0;
    }
    

    Summary

    这道题的思路不是很难,结果在码码的过程中出现了很多SB错误,调了我一个小时才调出来...

  • 相关阅读:
    Confluence 6 创建你的个人空间
    Win10正式专业版激活方法
    还在手工写接口测试文档,已经out了
    MYSQL支持的数据类型-数值类型
    mysql
    转 聊聊连接池和线程
    当压测数据压不上去时可能是哪些原因造成的
    IDEA自动导包(全局设置)
    微服务化后缓存怎么做
    win10家庭版升级到专业版密钥
  • 原文地址:https://www.cnblogs.com/xunzhen/p/9710438.html
Copyright © 2011-2022 走看看