题目跟2245是类似的。
主要用到了最小生成树求最大值,因为最小生成树是从小到大排序的。
排序用到了克里斯卡尔的算法。
用LCA算法求出最近公共祖先,再在求最近公共祖先的路上,一直取最大的值。就成功得到了最小生成树中的最大值
//prim没试过。应该可以
```
#include<bits/stdc++.h>
using namespace std;
const int N=1e6;
#define inf 0x3f3f3f3f;
int depth[N],n,m,cnt,fa[N][30],fi[N],ba[N],w[N][30],q,mst;
bool isv[N];//isv访问 depth深度 cnt不想解释。。
//fa倍增保存祖先 ba求父亲(爸) w存最大边权值 mst是MST算法。。
struct Mo
{
int from,to,w;
bool operator<(Mo a)const{return w<a.w;}//重载取最小生成树
}e[N];//存边
struct li
{
int to,w,nxt;
}eg[N];//用来连接
inline int find(register int x)
{
return ba[x]=(ba[x]==x?x:find(ba[x]));
}//路径压缩加找父亲
inline void add(register int x,register int y,register int w)
{
eg[++cnt].to=y,eg[cnt].w=w,eg[cnt].nxt=fi[x];
fi[x]=cnt;
}//链式前向星的添加
inline int read()
{
register int r=0,f=1;
register char e=getchar();
while(!isdigit(e))
{
if(e=='-')
f=-1;
e=getchar();
}
while(isdigit(e))
r=(r<<1)+(r<<3)-'0'+e,e=getchar();
return f*r;
}//快读,这个比较有用
inline void out(register int x)
{
if(x>9)
out(x/10);
putchar(x%10+'0');
}//快输,其实这个没啥效率
inline void init()
{
memset(fi,0,sizeof(fi));
cnt=0,mst=0;
memset(isv,0,sizeof(isv));
}//初始化
inline void kruskal()
{
sort(e+1,e+1+m);//调用排序
for(register int i=1;i<=m;i++)
{
register int x=find(e[i].from),y=find(e[i].to);
if(x!=y)
{
ba[x]=y;
add(e[i].from,e[i].to,e[i].w);
add(e[i].to,e[i].from,e[i].w);//双向链接,用前向星。
mst++;
if(mst==n-1)break;//好像不加这个限制也是可以过的
}
}
}//求最小生成树
inline void dfs(int x)
{
isv[x]=true;
for(register int i=fi[x];i;i=eg[i].nxt)
{
register int to=eg[i].to;
if(isv[to])continue;//被访问过就继续
depth[to]=depth[x]+1;//否则深度加1
fa[to][0]=x;//保存父亲
w[to][0]=eg[i].w;//保存父亲权值
dfs(to);
}
return ;
}//搜索计算深度,初始化fa,w
inline int LCA(register int x,register int y)
{
if(find(x)!=find(y))return -1;
register int ans=0;
if(depth[x]<depth[y])swap(x,y);
for(register int i=25;i>=0;i--)//25也可以用log2(K)K=n
if(depth[fa[x][i]]>=depth[y])ans=max(ans,w[x][i]),x=fa[x][i];//ans和x不能调换顺序,先取最大在更新,是存最大权值
if(x==y)return ans;
for(register int i=25;i>=0;i--)
if(fa[x][i]!=fa[y][i])
ans=max(ans,max(w[x][i],w[y][i])),x=fa[x][i],y=fa[y][i];
ans=max(ans,max(w[x][0],w[y][0]));//同上
return ans;
}//求公共祖先
int main()
{
int flag=0;
while(scanf("%d%d",&n,&m)==2)
{
if(flag!=0)putchar(10);
else
{
flag=1;
}//这个是很坑很坑的一个点。坑了一天。最后一组数据不能多空行
for(register int i=1;i<=m;i++)
e[i].from=read(),e[i].to=read(),e[i].w=read();
for(register int i=1;i<=n;i++)
ba[i]=i;
kruskal();
for(register int i=1;i<=n;i++)
{
if(!isv[i])
{
depth[i]=1;
dfs(i);
fa[i][0]=i;
w[i][0]=-1;//初始化
}
}
for(register int i=1;i<=25;i++)
for(register int j=1;j<=n;j++)
{
fa[j][i]=fa[fa[j][i-1]][i-1];
w[j][i]=max(w[j][i-1],w[fa[j][i-1]][i-1]);
}//倍增求最大值
q=read();
for(register int i=1;i<=q;i++)
{
register int x=read(),y=read();
int z=LCA(x,y);
printf("%d",z);
putchar(10);
}
init();多组数据所以再初始化
}
return 0;
}
```
(~~蒟蒻~~)第一次写题解,多多支持,对了对了,顺便安利一波新博客https://www.cnblogs.com/sscdg/;
洛谷题解 UVA11354 【Bond】 瓶颈树+kruskal+最小公共祖先
猜你喜欢
转载自www.cnblogs.com/sscdg/p/11412592.html
今日推荐
周排行