BZOJ 3732: Network(Kruskal重构树)

传送门

解题思路

  \(Kruskal\)重构树模板题,\(Kruskal\)重构树就是在建最小生成树加边的时候,不直接加边,而是新建一个点,而这个点的权值就是边权,这个新建的点作为原先点的父亲,并且把他们并起来。最终会得到一棵树,这个树有很多优秀的性质,首先它的叶结点都为原先的点,非叶结点为原先的边,还有从向下权值单调不减。那么这道题其实就算把\(Kruskal\)重构树建出来后两个点\(LCA\)的权值。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>

using namespace std;
const int N=30005;

inline int rd(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return f?x:-x;
}

int n,m,q,f[N][20],head[N],to[N],nxt[N],w[N],tot;
int F[N],cnt,num,dep[N];
struct Edge{
	int u,v,w;
	friend bool operator<(const Edge A,const Edge B){
		return A.w<B.w;
	}
}edge[N];

int get(int x){
	if(x==F[x]) return x;
	return F[x]=get(F[x]);
}

inline void add(int bg,int ed){
	to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
}

void dfs(int x,int FA){
	f[x][0]=FA;
	for(int i=1;i<=16;i++) 
		f[x][i]=f[f[x][i-1]][i-1];
	for(int i=head[x];i;i=nxt[i])
		dep[to[i]]=dep[x]+1,dfs(to[i],x);
}

inline int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=16;~i;i--)
		if(dep[f[x][i]]>=dep[y]) x=f[x][i];
	if(x==y) return x;
	for(int i=16;~i;i--)
		if(f[x][i]!=f[y][i])
			x=f[x][i],y=f[y][i];
	return f[x][0];
}

int main(){
	n=rd(),m=rd(),q=rd();num=n;
	for(int i=1;i<=n;i++) F[i]=i;
	for(int i=1;i<=m;i++)
		edge[i].u=rd(),edge[i].v=rd(),edge[i].w=rd();
	sort(edge+1,edge+1+m);int x,y;
	for(int i=1;i<=m;i++){
		x=get(edge[i].u),y=get(edge[i].v);
		if(x==y) continue;tot++;
		F[x]=y;w[++num]=edge[i].w;F[num]=num;
		F[x]=num;F[y]=num;add(num,x);add(num,y);
		if(tot==n-1) break;
	}
	dfs(num,0);
	while(q--){
		x=rd(),y=rd();
		printf("%d\n",w[lca(x,y)]);
	}
	return 0;
}
posted @ 2019-01-15 22:28  Monster_Qi  阅读(135)  评论(0编辑  收藏  举报