kruskal重构树

比较好理解,相当于重建了一个二叉树,所有的父亲节点都为原来图中的边,儿子节点为点。
重构树就可以利用lca求两点间的最大(或者最小)边权以及一些树上操作。

较为简单的应用,需要用线段树来维护信息。

点击查看代码
#include<bits/stdc++.h>
using namespace std;

const int N=1e6;
int n,m,q;
int f[N][40],fa[N],tme[N];
int ls[N],rs[N],dis[N];

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


int dep[N];
void dfs(int u,int fat)
{
	dep[u]=dep[fat]+1;
	f[u][0]=fat;
	for(int i=1;i<=30;i++) f[u][i]=f[f[u][i-1]][i-1];
	if(ls[u]!=0) dfs(ls[u],u);
	if(rs[u]!=0) dfs(rs[u],u); 
}

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

#define lson (rt<<1)
#define rson (rt<<1|1)

void pushup(int rt)
{
	dis[rt]=lca(dis[lson],dis[rson]);
}

void build(int rt,int l,int r)
{
	if(l==r) 
	{
		dis[rt]=l;
		return ;
	}
	int mid=(l+r)>>1;
	build(lson,l,mid); build(rson,mid+1,r);
	pushup(rt);
}

int query(int rt,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return dis[rt];
	int mid=(l+r)>>1;
	int ans=0;
	if(L<=mid) ans=query(lson,l,mid,L,R);
	if(R>mid) ans= ans==0?query(rson,mid+1,r,L,R):lca(ans,query(rson,mid+1,r,L,R));
	return ans; 
} 

int main()
{

	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n*2-1;i++) fa[i]=i;
	for(int i=1;i<=n*2-1;i++) ls[i]=rs[i]=tme[i]=0;
	int cnt=n;
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		int fx=find(x),fy=find(y);
		if(fx!=fy)
		{
			int u=++cnt;
			tme[u]=i;
			ls[u]=fx;
			rs[u]=fy;
			fa[fx]=fa[fy]=u;
		} 
	}
	dfs(cnt,0);
	build(1,1,n);
	for(int i=1;i<=q;i++)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		printf("%d\n",tme[query(1,1,n,l,r)]);
	}	
	
} 
posted @ 2024-07-26 19:37  zhengchenxi  阅读(37)  评论(4编辑  收藏  举报