题目链接:https://www.luogu.com.cn/problem/P1967
这题我们可以知道有些边是肯定不会用到的,所以我们想办法去边。把这个图的最大生成树求出来即可。然后求两点的最小限重,用树上倍增求LCA,过程种更新最小限重。
代码如下
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
const int maxm=5e4+5;
const int inf=0xfffffff;
struct Node
{
int x,y,w;
}edge1[maxm];//存原图
struct node
{
int to,next,value;
}edge2[maxm*2];//存最大生成树
//无向边开两倍
int cnt;
int n,m,q;
int head[maxn];
int f[maxn];//存祖先节点
int fa[maxn][21];//存生成树父节点
int weight[maxn][21];//存最小限重
int depth[maxn];//存每个点深度
void add(int x,int y,int z)//生成树加边
{
edge2[++cnt].next=head[x];
edge2[cnt].to=y;
edge2[cnt].value=z;
head[x]=cnt;
}
int find(int x)//并查集找祖先
{
if(x==f[x])
return x;
return f[x]=find(f[x]);
}
bool cmp(Node a,Node b)//权值大的优先
{
return a.w>b.w;
}
void kruskal()
{
sort(edge1+1,edge1+1+m,cmp);//先排序
for(int i=1;i<=n;i++)
f[i]=i;//初始祖先节点是自己
for(int i=1;i<=m;i++)
{
int fx=find(edge1[i].x),fy=find(edge1[i].y);
if(fx!=fy)
{
f[fx]=fy;
add(edge1[i].x,edge1[i].y,edge1[i].w);
add(edge1[i].y,edge1[i].x,edge1[i].w);//无向边存两次
}
}
}
void dfs(int x)
{
for(int i=head[x];i;i=edge2[i].next)
{
int v=edge2[i].to;
if(fa[x][0]==v)
continue;
int c=edge2[i].value;
depth[v]=depth[x]+1;
fa[v][0]=x;//v的父节点为x
weight[v][0]=c;//存限重
dfs(v);
}
}
int gmin(int x,int y)//手写取最小值
{
if(x>y)
return y;
return x;
}
void init()
{
for(int i=1;i<=20;i++)
for(int j=1;j<=n;j++)
{
fa[j][i]=fa[fa[j][i-1]][i-1];
weight[j][i]=gmin(weight[j][i-1],weight[fa[j][i-1]][i-1]);
}
}
int lca(int x,int y)
{
if(find(x)!=find(y))
return -1;//不可达
if(depth[x]>depth[y])
swap(x,y);//保证y为深度大的
int ans=inf;//答案
for(int i=20;i>=0;i--)//使y深度与x深度相等
if(depth[fa[y][i]]>=depth[x])
{
ans=gmin(ans,weight[y][i]);
y=fa[y][i];
}
if(x==y)//已经到了
return ans;
for(int i=20;i>=0;i--)
{
if(fa[x][i]!=fa[y][i])//父节点不一样才能跳
{
ans=gmin(ans,gmin(weight[x][i],weight[y][i]));
x=fa[x][i];
y=fa[y][i];
}
}
//别忘了到最近祖先节点还要取一次最小值
ans=gmin(ans,gmin(weight[x][0],weight[y][0]));
return ans;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&edge1[i].x,&edge1[i].y,&edge1[i].w);
}
kruskal();
for(int i=1;i<=n;i++)
if(!fa[i][0])
{
dfs(i);
fa[i][0]=i;
weight[i][0]=inf;
}
init();//LCA初始化
scanf("%d",&q);
while(q--)
{
int x,y;
scanf("%d %d",&x,&y);
printf("%d\n",lca(x,y));
}
return 0;
}
来源:CSDN
作者:nefu_cbw
链接:https://blog.csdn.net/weixin_44491423/article/details/104541501