原题:qwb与学姐
原题大意
qwb打算向学姐表白,可是学姐已经受够了他的骚扰,于是出了一个题想难住他:已知一幅n个点m条边的无向图,定义 路径的值为这条路径上最短的边的长度,现在有k个询问,询问从A点到B点的所有路径的值的最大值。
算法分析
题目意思是查询图上两点的瓶颈路大小,这个训练指南上有讲解。
先是求最大生成树,然后求树上两点路径的最小值,用LCA倍增法就可以了。
http://blog.csdn.net/Janis_z/article/details/52937631?locationNum=6&fps=1
程序代码
template <class T> inline void umin(T &a,T b){a=min(a,b);}
template <class T> inline void umax(T &a,T b){a=max(a,b);}
const int N=50005;
struct Bian{
int u;
int v;
int w;
};
int p[N],ra[N];
Bian bian[200005];
vector<pii> G[N];
bool cmp(const Bian &p1,const Bian &p2){
return p1.w>p2.w;
}
int find(int x){
return p[x]==x?x:p[x]=find(p[x]);
}
int Union(int x,int y) {
x=find(x);
y=find(y);
if(x==y)return 0;
if(ra[x]>ra[y]) {
p[y]=x;
}else{
if(ra[x]==ra[y])ra[y]++;
p[x]=y;
}
return 1;
}
void Kruskal(int kn,int km){
for(int i=1;i<=kn;i++){
p[i]=i;
}
sort(bian,bian+km,cmp);
for(int i=0;i<km;i++){
if(Union(bian[i].u,bian[i].v)){
G[bian[i].u].push_back({bian[i].v,bian[i].w});
G[bian[i].v].push_back({bian[i].u,bian[i].w});
}
}
}
int d[N][20],f[N][20];
int dep[N];
void dfs(int u,int fa){
dep[u]=dep[fa]+1;
for(int i=0;i<G[u].size();i++){
int v=G[u][i].ff;
if(v==fa)continue;
f[v][0]=u;
d[v][0]=G[u][i].ss;
dfs(v,u);
}
}
int main() {
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=0;i<m;i++){
scanf("%d%d%d",&bian[i].u,&bian[i].v,&bian[i].w);
}
Kruskal(n,m);
dep[1]=1;
dfs(1,0);
int wc=0;//log深度
for(int i=1;;wc++){
i<<=1;
if(i>n)break;
}
for(int j=1;j<=wc;j++){
for(int i=1;i<=n;i++){
f[i][j]=f[f[i][j-1]][j-1];
d[i][j]=min(d[i][j-1],d[f[i][j-1]][j-1]);
}
}
while(q--){
int x,y;
scanf("%d%d",&x,&y);
int ans=INF;
if(dep[x]<dep[y])swap(x,y);
for(int i=wc;i>=0;i--){
if(dep[f[x][i]]>=dep[y]){
umin(ans,d[x][i]);
x=f[x][i];
if(dep[x]==dep[y])break;
}
}
//如果xy不在同一侧
if(x!=y){
for(int i=wc;i>=0;i--){
if(f[x][i]!=f[y][i]){
umin(ans,d[x][i]);
umin(ans,d[y][i]);
x=f[x][i];
y=f[y][i];
}
}
//到0倍父亲
umin(ans,d[x][0]);
umin(ans,d[y][0]);
}
printf("%d\n",ans);
}
return 0;
}