• BZOJ 1977 次小生成树


    传送门

    题目大意:

    求严格次小生成树(权值和严格小于最小生成树)

    题目分析:

    和无限制的次小生成树一样,唯一不同的是,严格小于,只需要将删除非树边连接的两点树链上的最长边改为删除1.如果最长边不等于该边,就直接计算2.如果等于,就用次长边计算。
    在最小生成树上倍增即可。

    code

    #include<bits/stdc++.h>
    using namespace std;
    namespace IO{
    	template<typename T>
    	inline T read(){
    		T i = 0, f = 1; char ch = getchar();
    		for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
    		if(ch == '-') ch = getchar(), f = -1;
    		for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
    		return i * f;
    	}
    	template<typename T>
    	inline void wr(T x){
    		if(x < 0) putchar('-'), x= - x;
    		if(x > 9) wr(x / 10);
    		putchar(x % 10 + '0');
    	}
    }using namespace IO;
    
    const int N = 1e5+5, M = 3e5+5;
    const long long OO = 2e18;
    long long ans1 = 0, ans2 = OO;
    int n, m;
    int ecnt, adj[N], nxt[M << 1], go[M << 1], len[M <<1];
    int anc[N], dep[N];
    int fa[N][25];
    long long maxx[N][25];
    bool used[M];
    
    struct node{
    	int x, y, c;
    	inline bool operator < (const node &b) const{
    		return c < b.c;
    	}
    	inline void load(){
    		x = read<int>(), y = read<int>(), c = read<int>();
    	}
    }edge[M];
    
    inline void addEdge(int u, int v, int c){
    	nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v, len[ecnt] = c;
    }
    
    inline int getAnc(int x){
    	return x == anc[x] ? x : (anc[x] = getAnc(anc[x]));
    }
    
    inline void dfs(int u, int f, int ee){
    	fa[u][0] = f;
    	dep[u] = dep[f] + 1;
    	maxx[u][0] = len[ee];
    	for(int i = 1; i <= 20; i++){
    		fa[u][i] = fa[fa[u][i - 1]][i - 1];
    		maxx[u][i] = max(maxx[u][i - 1], maxx[fa[u][i - 1]][i - 1]);
    	}
    	for(int e = adj[u]; e; e = nxt[e]){
    		int v = go[e];
    		if(v == f) continue;
    		dfs(v, u, e);
    	}
    }
    
    inline pair<long long, long long> get(int u, int v){
    	//int lca = getLca(u, v);
    	long long ma1 = -OO, ma2 = -OO;
    	if(dep[u] < dep[v]) swap(u, v);
    	int delta = dep[u] - dep[v];
    	for(int i = 20; i >= 0; i--){
    		if(delta & (1 << i)){
    			if(maxx[u][i] > ma1){
    				ma2 = ma1;
    				ma1 = maxx[u][i];
    			}
    			else if(maxx[u][i] > ma2)
    				ma2 = maxx[u][i];
    			u = fa[u][i];
    		}
    	}
    	if(u == v) return make_pair(ma1, ma2);
    	for(int i = 20; i >= 0; i--){
    		if(fa[u][i] != fa[v][i]){
    			if(maxx[v][i] > ma1){
    				ma2 = ma1;
    				ma1 = maxx[v][i];
    			}
    			else if(maxx[v][i] > ma2)
    				ma2 = maxx[v][i];
                v = fa[v][i];
    			//-----------------------------
    			if(maxx[u][i] > ma1){
    				ma2 = ma1;
    				ma1 = maxx[u][i];
    			}
    			else if(maxx[u][i] > ma2)
    				ma2 = maxx[u][i];
    			u = fa[u][i];
    		}
    	}
    	if(maxx[v][0] > ma1){
            ma2 = ma1;
            ma1 = maxx[v][0];
        }
        else if(maxx[v][0] > ma2)
            ma2 = maxx[v][0];
        //-----------------------------
        if(maxx[u][0] > ma1){
            ma2 = ma1;
            ma1 = maxx[u][0];
        }
        else if(maxx[u][0] > ma2)
            ma2 = maxx[u][0];
    	return make_pair(ma1, ma2);
    }
    
    int main(){
    	freopen("h.in", "r", stdin);
    	n = read<int>(), m = read<int>();
    	for(int i = 1; i <= n; i++) anc[i] = i;
    	for(int i = 1; i <= m; i++)
    		edge[i].load();
    	sort(edge + 1, edge + m + 1);
    	for(int i = 1; i <= m; i++){
    		int fx = getAnc(edge[i].x), fy = getAnc(edge[i].y);
    		if(fx != fy){
    			anc[fx] = fy;
    			ans1 += 1ll*edge[i].c;
    			addEdge(edge[i].x, edge[i].y, edge[i].c);
    			addEdge(edge[i].y, edge[i].x, edge[i].c);
    			used[i] = true;
    		}
    	}
    	for(int i = 1; i <= n; i++)
            for(int j = 0; j <= 25; j++)
                maxx[i][j] = OO;
    	dfs(1, 0, 0);
    	for(int i = 1; i <= m; i++){
            if(used[i]) continue;
    		pair<int, int> ret = get(edge[i].x, edge[i].y);
    		//cout<<edge[i].x<<" "<<edge[i].y<<" "<<ret.first<<" "<<ret.second<<endl;
    		int delta = ret.first == edge[i].c ? ret.second : ret.first;
    		ans2 = min(ans2, ans1 - delta + edge[i].c);
    	}
    	printf("%lld", ans2);
    	return 0;
    }
    
    
  • 相关阅读:
    使用jQuery对象
    jQuery插件
    使用jQuery函数
    jQuery的两把利器
    初始jQuery
    BOM——特效
    BOM的介绍
    DOM——节点操作
    miaov- 自动生成正V反V大于号V小于号V楼梯等图案
    H5 -- 本地存储计数器的值 和前端校验用户
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7747775.html
Copyright © 2020-2023  润新知