bzoj1977 [BeiJing2010组队]次小生成树 Tree

[BeiJing2010组队]次小生成树 Tree

Time Limit: 10 Sec Memory Limit: 512 MB

Description

小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值)

这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

Input

第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

Output

包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

Sample Input

5 6

1 2 1

1 3 2

2 4 3

3 5 4

3 4 3

4 5 6

Sample Output

11

HINT

数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。

实际上你要先求出最小生成树,然后再在这个基础上改一点点就变成了次小生成树。
具体来说就是找一条以前没有用的边,然后把这两点原来路径上的一条最大的边给砍了。。。
然后题目很变态的要求严格小于。。。你还要记第二小的边。。。。
最开始偷懒用set。。。被卡常了。。。
然后最后4分钟卡常大师重出江湖。。。。一手sort直接*过。。。




#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
struct lpl{
	int from, to, dis;
	bool flag;
}lin;
struct ld{
	int to, dis;
}qwe;
struct lpd{
	int fa, dis, deep, tree[18][3];
}node[maxn];
int n, m, root, pw[25], fa[maxn];
int tot, aaa[maxn];
long long sum = 0, ans = 1e14 + 5;
set<int> s;
set<int>::iterator iter;
vector<lpl> edge;
vector<ld> point[maxn];

inline int read()
{  
   int s = 0, w = 1;  char ch = getchar();  
   while(ch <= '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}  
   while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();  
   return s * w;  
}  

inline bool cmp(lpl A, lpl B){return A.dis < B.dis;}

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

inline void putit()
{
	n = read(); m = read(); root = 1; pw[0] = 1;
	for(int a, b, i = 1; i <= m; ++i){
		scanf("%d%d%d", &lin.from, &lin.to, &lin.dis); edge.push_back(lin);
	}
	for(int i = 1; i <= 17; ++i) pw[i] = pw[i - 1] * 2;
}

inline void kruskal()
{
	for(int i = 1; i <= n; ++i) fa[i] = i;
	sort(edge.begin(), edge.end(), cmp); int N = edge.size() - 1;
	for(int A, B, i = 0; i <= N; ++i){
		A = find(edge[i].from); B = find(edge[i].to);
		if(A == B) continue;
		fa[A] = B; qwe.to = edge[i].to; qwe.dis = edge[i].dis; 
		sum += (long long)qwe.dis; edge[i].flag = true;
		point[edge[i].from].push_back(qwe); qwe.to = edge[i].from;
		point[edge[i].to].push_back(qwe);
	}
}

void build(int t)
{
	for(int i = point[t].size() - 1; i >= 0; --i){
		int now = point[t][i].to;
		if(now == node[t].fa) continue;
		node[now].fa = t; node[now].dis = point[t][i].dis; node[now].deep = node[t].deep + 1;
		build(now);
	}
}

void prepare(int t)
{
	node[t].tree[0][0] = node[t].fa; node[t].tree[0][1] = node[t].dis;
	for(int i = 1; i <= 17; ++i){
		if(pw[i] > node[t].deep) break;
		node[t].tree[i][0] = node[node[t].tree[i - 1][0]].tree[i - 1][0];
//		s.insert(node[node[t].tree[i - 1][0]].tree[i - 1][1]);
//		s.insert(node[node[t].tree[i - 1][0]].tree[i - 1][2]);
//		s.insert(node[t].tree[i - 1][1]);
//		s.insert(node[t].tree[i - 1][2]);
//		for(iter = s.begin(); iter != s.end(); ++iter){
//			node[t].tree[i][2] = node[t].tree[i][1]; node[t].tree[i][1] = *iter;
//		}
//		s.clear();
		tot = 0;
		aaa[++tot] = node[node[t].tree[i - 1][0]].tree[i - 1][1];
		aaa[++tot] = node[node[t].tree[i - 1][0]].tree[i - 1][2];
		aaa[++tot] = node[t].tree[i - 1][1];
		aaa[++tot] = node[t].tree[i - 1][2];
		sort(aaa + 1, aaa + tot + 1); node[t].tree[i][1] = aaa[tot];
		for(int k = tot - 1; k >= 1; --k){
			if(aaa[k] != node[t].tree[i][1]){
				node[t].tree[i][2] = aaa[k]; break;
			}
		}
	}
	for(int now, i = point[t].size() - 1; i >= 0; --i){
		now = point[t][i].to;
		if(now == node[t].fa) continue;
		prepare(now);
	}
}

inline void workk()
{
	for(int A, B, lca, mx, i = edge.size() - 1; i >= 0; --i){
		lin = edge[i]; A = lin.from; B = lin.to; mx = 0; tot = 0;
		if(edge[i].flag) continue;
		if(node[A].deep < node[B].deep) swap(A, B);
		for(int k = 17; k >= 0; --k){
			if(node[A].deep == node[B].deep) break;
			if(node[node[A].tree[k][0]].deep >= node[B].deep && node[A].tree[k][0]){
				//s.insert(node[A].tree[k][1]); s.insert(node[A].tree[k][2]);
				aaa[++tot] = node[A].tree[k][1]; aaa[++tot] = node[A].tree[k][2];
				A = node[A].tree[k][0]; 
			}
		}
		if(A != B){
			for(int k = 17; k >= 0; --k){
				if(node[A].tree[k][0] != node[B].tree[k][0]){
//					s.insert(node[A].tree[k][1]); s.insert(node[A].tree[k][2]);
//					s.insert(node[B].tree[k][1]); s.insert(node[B].tree[k][2]);
					aaa[++tot] = node[A].tree[k][1]; aaa[++tot] = node[A].tree[k][2];	
					aaa[++tot] = node[B].tree[k][1]; aaa[++tot] = node[B].tree[k][2];
					A = node[A].tree[k][0]; B = node[B].tree[k][0];
				}
			}	
			aaa[++tot] = node[A].dis; aaa[++tot] = node[B].dis;
			//s.insert(node[A].dis); s.insert(node[B].dis); 
			lca = node[A].fa;		
		}
		if(A == B) lca = A;
//		for(iter = s.begin(); iter != s.end(); ++iter){
//			if(*iter != lin.dis) mx = max(mx, *iter);
//		}
//		s.clear();
		sort(aaa + 1, aaa + 1 + tot);
		for(int i = tot; i >= 1; --i){
			if(aaa[i] != lin.dis){
				mx = aaa[i]; break;
			}
		}
		ans = min(ans, sum + lin.dis - mx);
	}
}

int main()
{
	putit();
	kruskal();
	build(root);
	prepare(root);
	workk();
	cout << ans;
	return 0;
}

心如花木,向阳而生。
posted @ 2018-06-22 22:06  沛霖  阅读(90)  评论(0编辑  收藏  举报