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

posted @ 2017-10-28 19:15  CzYoL  阅读(165)  评论(0编辑  收藏  举报