LCA解决瓶颈问题

以前一直以为要特意怎么样去弄,后来才知道只要在LCA倍增的过程中顺带着往上求出最小值就可以了,毕竟一段距离总是可以被拿二的几次方表示出来的,所以一定可以覆盖住每一段的最小值
时间有限,先放代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int head[500000];
int head2[500000];
int q;
int n,m;
struct Edge
{
	int from;
	int to;
	int next;
	int w;
	friend bool operator <(Edge a,Edge b)
	{
		return a.w<b.w;
	}
} edge[500000],edge2[50000];
int cnt=1;
void add(int u,int v,int len)
{
	edge[cnt].from=u;
	edge[cnt].to=v;
	edge[cnt].w=len;
	edge[cnt].next=head[u];
	head[u]=cnt++;
}
void add2(int u,int v,int len)
{
	edge2[cnt].from=u;
	edge2[cnt].to=v;
	edge2[cnt].w=len;
	edge2[cnt].next=head2[u];
	head2[u]=cnt++;
}
int pre[500000];
int find(int x)
{
	if(pre[x]==x)
		return x;
	else
	{
		pre[x]=find(pre[x]);
		return pre[x];//直接把它的父亲节点归到祖宗节点上
	}
}
void Union(int x,int y)
{
	//如果两者不同属于同一集合
	pre[find(x)]=find(y);//把x的祖宗归到y的祖宗身上
}
bool cmp(Edge a,Edge b)
{
	return a.w>b.w;
}
int d[500000][40];//d[i][j]表示i点上翻2的j次方个点(也就是有2的j次方个边)的最小值! 
int f[500000][40];
int deep[500000];//方便计算LCA的一个东西!
int fa[500000];
bool vis[500000];
void dfs(int father,int u,int w)
{
	vis[u]=true;
	fa[u]=father;
	f[u][0]=father;
	d[u][0]=w; //记住,在树中,我们都上翻而不是下翻!
	deep[u]=deep[father]+1;
	for(int i=head2[u]; i!=-1; i=edge2[i].next)
	{
		int vi=edge2[i].to;
		int w1=edge2[i].w;
		if(vi==father)
			continue;
		if(!vis[vi])
			dfs(u,vi,w1);
	}
	return;
}
void lca_init()
{
	for(int j=1; j<=30; j++)
		for(int i=1; i<=n; i++)
		{
			f[i][j]=f[f[i][j-1]][j-1];
		}
	for(int j=1; j<=30; j++)
		for(int i=1; i<=n; i++)
		{
			d[i][j]=min(d[i][j-1],d[f[i][j-1]][j-1]);//集成父亲
		}//算的不就是这俩吗?费事!
	return;
}
int lca(int x,int y)
{
	if(deep[x]<deep[y])swap(x,y);//令x深度最大
	int mi=0x7fffffff;
	for(int j=30; j>=0; j--)
	{
		if(deep[f[x][j]]>=deep[y])
		{
			mi=min(mi,d[x][j]);//每次二进制上翻时顺带算上就好
			x=f[x][j];
		}
		if(x==y)return mi;//向上翻但x仍然大于等于y
	}
	for(int j=30; j>=0; j--)
	{
		if(f[x][j]!=f[y][j])
		{
			mi=min(mi,d[x][j]);
			mi=min(mi,d[y][j]);//先把上回的处理完 
			x=f[x][j];y=f[y][j];
		}
	}
	mi=min(mi,d[x][0]);
	mi=min(mi,d[y][0]);
	return mi;
}

int main()
{
	memset(head,-1,sizeof(head));
	memset(head2,-1,sizeof(head2));
	scanf("%d%d",&n,&m);
	int x,y,z;
	int q;
	for(int i=1; i<=n; i++)
		pre[i]=i;
	for(int i=1; i<=m; i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
	}
	sort(edge+1,edge+1+m,cmp);//对各边重新排序
	cnt=1;
	for(int i=1; i<=m; i++)
	{
		x=edge[i].from;
		y=edge[i].to;
		z=edge[i].w;
		int ab=find(x);
		int cd=find(y);
		if(ab!=cd)
		{
			Union(x,y);
			add2(x,y,z);
			add2(y,x,z);//重新建边
		}
	}
	for(int i=0; i<=n; i++)
	{
		for(int j=0; j<=20; j++)
		{
			d[i][j]=0x7fffffff;
		}
	}
	dfs(0,1,0);
	scanf("%d",&q);
	lca_init();
	for(int i=1; i<=q; i++)
	{
		scanf("%d%d",&x,&y);
		if(find(x)!=find(y))
		{
			printf("-1\n");
			continue;
		}
		int ans=lca(x,y);
		printf("%d\n",ans);
	}
}
posted @ 2022-02-16 17:08  liangchenming  阅读(38)  评论(0编辑  收藏  举报