Kruskal重构树

Kruskal重构树是基于Kruskal算法的,典型的应用是求两点之间边权最大值的最小值。


首先,我们运行Kruskal算法,将边从小到大排列,在运行过程中,每加入一条边,就建立一个节点u,权值为边权的权值w,然后所连两点a,b所在子树的根节点作为它的儿子,就像这样:


由于边是按升序加入的,所以这棵二叉树为大根堆,如果需要求两点之间在生成树中路径上最大权值,那么求两点LCA就好了



BZOJ3732

板题

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
using namespace std;
const int maxn=30005,maxv=100005,maxm=100005,INF=2000000000,P=1000000007;

inline int read(){
	int out=0,flag=1;char c=getchar();
	while(c<48||c>57) {if(c=='-') flag=-1;c=getchar();}
	while(c>=48&&c<=57){out=out*10+c-48;c=getchar();}
	return out*flag;
}

int N,M,K;

struct EE{
	int a,b,w;
}Edge[maxm];

inline bool operator <(const EE& a,const EE& b){
	return a.w<b.w;
}

int head[maxv],nedge = 0;
struct EDGE{
	int to,next;
}edge[maxm];

inline void build(int a,int b){
	edge[nedge] = (EDGE){b,head[a]};
	head[a] = nedge++;
	edge[nedge] = (EDGE){a,head[b]};
	head[b] = nedge++;
}

void init(){
	fill(head,head+maxv,-1);
	N = read();
	M = read();
	K = read();
	for(int i=1; i<=M; i++){
		Edge[i].a = read();
		Edge[i].b = read();
		Edge[i].w = read();
	}
}

int nodei=0,pre[maxv],v[maxn];

inline int find(int x){return x == pre[x] ? x : pre[x]=find(pre[x]);}

void kruskal(){
	sort(Edge+1,Edge+1+M);
	for (int i = 1; i <= N; i++) pre[i]=i;
	nodei=N;
	int fa,fb;
	for (int i = 1; i <= M; i++){
		fa = find(Edge[i].a);
		fb = find(Edge[i].b);
		if (fa != fb){
			v[++nodei] = Edge[i].w;
			pre[fa] = pre[fb] = pre[nodei] = nodei;
			build(fa,nodei);
			build(fb,nodei);
		}
	}
}

bool vis[maxv];
int top[maxv],son[maxv],fa[maxv],siz[maxv],dep[maxv];

void dfs1(int u,int f,int d){
	fa[u] = f;dep[u] = ++d;siz[u] = 1;vis[u] = true;
	int to;
	for (int k = head[u]; k != -1; k = edge[k].next)
		if ((to = edge[k].to) != f){
			dfs1(to,u,d);
			siz[u] += siz[to];
			if (!son[u]||siz[to] > siz[son[u]]) son[u] = to;
		}
}

void dfs2(int u,int flag){
	top[u] = flag ? top[fa[u]] : u;
	int to;
	if (son[u]) dfs2(son[u],true);
	for (int k = head[u]; k != -1; k = edge[k].next)
		if ((to = edge[k].to) != son[u]&&to != fa[u])
			dfs2(to,false);
}

void division(){
	for (int i = 1; i <= nodei; i++)
		if (!vis[i]){
			dfs1(find(i),0,0);
			dfs2(find(i),0);
		}
}

int ask(int u,int v){
	while (top[u] != top[v])
		dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
	return dep[u] > dep[v] ? v:u;
}

void solve(){
	while (K--) printf("%d\n",v[ask(read(),read())]);
}

int main(){
	init();
	kruskal();
	division();
	solve();
	return 0;
}

NOIP2013货车运输也是一道这样的题

posted @ 2017-09-19 12:56  Mychael  阅读(167)  评论(0编辑  收藏  举报