题目大意:给定一个n个点m条边的无向连通图,k次询问两点之间所有路径中最长边的最小值
Kruskal+倍增LCA做法见http://blog.csdn.net/popoqqq/article/details/39755703
LCT做法见http://blog.csdn.net/popoqqq/article/details/39929277
Kruskal重构树真是强大……一不小心手滑就RANK1啥的……
每加入一条边时,我们并不链接这条边的两端点,而是把这条边两端点所在并查集的根连接起来,而且是按秩合并
这样做的好处就是任何一个节点到根的路径长度不超过logn
且由于Kruskal重构树的性质,两点之间的最长边和原图相同,且最长边的一端连接的一定是两点的LCA
于是直接暴力向上找就行 如果加上倍增的话或许能优化到O(loglogn)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 15100
using namespace std;
struct abcd{
int x,y,f;
bool operator < (const abcd &Y) const
{
return f < Y.f ;
}
}edges[M<<1];
int n,m,k;
int belong[M],fa[M],size[M],dis[M],dpt[M];
int Find(int x)
{
if(!belong[x])
belong[x]=x,size[x]=1;
if(belong[x]==x)
return x;
return belong[x]=Find(belong[x]);
}
int Get_Depth(int x)
{
if(dpt[x]) return dpt[x];
if(!fa[x]) return dpt[x]=1;
return dpt[x]=Get_Depth(fa[x])+1;
}
void Kruskal()
{
int i;
sort(edges+1,edges+m+1);
for(i=1;i<=m;i++)
{
int x=Find(edges[i].x);
int y=Find(edges[i].y);
if(x==y) continue ;
if(size[x]>size[y])
swap(x,y);
belong[x]=y;
size[y]=max(size[y],size[x]+1);
fa[x]=y;
dis[x]=edges[i].f;
}
}
int Query(int x,int y)
{
int re=0;
if(dpt[x]<dpt[y])
swap(x,y);
while(dpt[x]>dpt[y])
re=max(re,dis[x]),x=fa[x];
while(x!=y)
re=max(re,dis[x]),re=max(re,dis[y]),x=fa[x],y=fa[y];
return re;
}
int main()
{
int i,x,y;
cin>>n>>m>>k;
for(i=1;i<=m;i++)
scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].f);
Kruskal();
for(i=1;i<=n;i++)
Get_Depth(i);
for(i=1;i<=k;i++)
{
scanf("%d%d",&x,&y);
printf("%d\n", Query(x,y) );
}
}