UVA - 11354 Bond(最小生成树+LCA+瓶颈路)

题意:N个点,M条路,每条路的危险度为路上各段中最大的危险度。多组询问,点s到点t的所有路径中最小的危险度。

分析:

1、首先建个最小生成树,则s到t的路径一定是危险度最小的。

原因:建最小生成树的最后一步,如果有两个相等的边可以选择,然后将两个连通块连在一起。

那不管选择哪个边,对于分别位于两个连通块的两点来说,这条边都是必经之路,而这个必经之路是这两点路径的危险度中最大的,起决定作用,所以选哪个是一样的。

2、利用lca,在找s和t最近公共祖先的过程中,不断取两者路径中的最大危险度即可。

3、d[k][v] 为点v到它向上走2k步所到的顶点的路径中最大的危险度。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#define lowbit(x) (x & (-x))
const double eps = 1e-8;
inline int dcmp(double a, double b){
    if(fabs(a - b) < eps) return 0;
    return a > b ? 1 : -1;
}
typedef long long LL;
typedef unsigned long long ULL;
const int INT_INF = 0x3f3f3f3f;
const int INT_M_INF = 0x7f7f7f7f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const LL LL_M_INF = 0x7f7f7f7f7f7f7f7f;
const int dr[] = {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[] = {-1, 1, 0, 0, -1, 1, -1, 1};
const int MOD = 1e9 + 7;
const double pi = acos(-1.0);
const int MAXN = 50000 + 10;
const int MAXT = 100000 + 10;
using namespace std;
struct Node{
    int a, b;
    Node(int aa, int bb):a(aa), b(bb){}
};
int N, M;
int fa[MAXN];
int d[20][MAXN];
int depth[MAXN];
int parent[20][MAXN];
vector<Node> G[MAXN];
int Find(int x){
    return fa[x] = (fa[x] == x) ? x : Find(fa[x]);
}
struct Edge{
    int x, y, d;
    void read(){
        scanf("%d%d%d", &x, &y, &d);
    }
    bool operator < (const Edge& rhs)const{
        return d < rhs.d;
    }
}num[MAXT];
void kruskal(){
    for(int i = 0; i < M; ++i){
        int tmpx = Find(num[i].x);
        int tmpy = Find(num[i].y);
        if(tmpx == tmpy) continue;
        G[num[i].x].push_back(Node(num[i].y, num[i].d));
        G[num[i].y].push_back(Node(num[i].x, num[i].d));
        if(tmpx < tmpy) fa[tmpy] = tmpx;
        else fa[tmpx] = tmpy;
    }
}
void dfs(int v, int fa, int deep){
    parent[0][v] = fa;
    depth[v] = deep;
    int len = G[v].size();
    for(int i = 0; i < len; ++i){
        if(G[v][i].a != fa){
            d[0][G[v][i].a] = G[v][i].b;
            dfs(G[v][i].a, v, deep + 1);
        }
    }
}
void LCA_init(){
    dfs(1, -1, 0);
    for(int k = 0; k + 1 < 20; ++k){
        for(int v = 1; v <= N; ++v){
            if(parent[k][v] < 0) parent[k + 1][v] = -1;
            else{
                parent[k + 1][v] = parent[k][parent[k][v]];
                d[k + 1][v] = max(d[k][v], d[k][parent[k][v]]);
            }
        }
    }
}
int lca(int u, int v){
    int ans = 0;
    if(depth[u] > depth[v]) swap(u, v);
    for(int k = 0; k < 20; ++k){
        if(((depth[v] - depth[u]) >> k) & 1){
            ans = max(ans, d[k][v]);
            v = parent[k][v];
        }
    }
    if(u == v) return ans;
    for(int k = 19; k >= 0; --k){
        if(parent[k][u] != parent[k][v]){
            ans = max(ans, d[k][u]);
            ans = max(ans, d[k][v]);
            u = parent[k][u];
            v = parent[k][v];
        }
    }
    ans = max(ans, d[0][u]);
    ans = max(ans, d[0][v]);
    return ans;
}
int main(){
    bool flag = true;
    while(scanf("%d%d", &N, &M) == 2){
        memset(parent, -1, sizeof parent);
        memset(d, 0, sizeof d);
        memset(depth, 0, sizeof depth);
        for(int i = 1; i < MAXN; ++i){
            fa[i] = i;
            G[i].clear();
        }
        for(int i = 0; i < M; ++i){
            num[i].read();
        }
        sort(num, num + M);
        kruskal();
        LCA_init();
        int Q;
        scanf("%d", &Q);
        if(flag) flag = false;
        else printf("\n");
        while(Q--){
            int s, t;
            scanf("%d%d", &s, &t);
            printf("%d\n", lca(s, t));
        }
    }
    return 0;
}

  

时间: 2024-10-12 16:59:29

UVA - 11354 Bond(最小生成树+LCA+瓶颈路)的相关文章

UVa 11354 Bond 最小生成树+LCA倍增

题目来源:UVa 11354 Bond 题意:n个点m条边的图 q次询问 找到一条从s到t的一条边 使所有边的最大危险系数最小 思路:使最大的危险系数尽量小 答案是最小生成树上的边 然后用LCA倍增法记录s和t到他们最近公共祖先的最大值 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 50010; const int INF =

UVA 11354 Bond(最小生成树+lca+倍增求祖先节点)

题意:n个点m条边,每条边有一个权值,有q个询问,每次询问两点间的一条路径,使得这条路径上权值最大的边最小. 思路:很容易想到最小瓶颈路,但是查询太多,会超时,可以预处理出最小生成树,则问题转化为一棵树上的两点间路径中权值最大的那条边,设这两点为u,v,可以得到dist(u,v)=max(dist(u,lca(u,v)),dist(v,lca(v,lca))),其中lca(u,v)表示u和v的最近公共祖先,用倍增的思想预处理出每个结点的2^i的祖先fa[u][i],然后在离线求出lca后顺便计算

uva 11354 bond 最小生成树

n个城市通过m条无向边连接,回答q个询问,每个询问形式为s,t,要找到一条s到t的路使得这条路上的最大危险系数最小. 还是最小瓶颈路,可是要快速回答每次询问,先求出最小生成树,转化为有根树,即找到s到t的路径上的最大边,在这一过程中倍增查找. 预处理的复杂度为nlogn,每次查询为logn. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using na

UVA 11354 - Bond (最小生成树 + 树链剖分)

题目链接~~> 做题感悟:这题开始看到时感觉不是树不好处理,一想可以用 Kruskal 处理成树 ,然后就好解决了. 解题思路: 先用 Kruskal 处理出最小生成树,然后用树链剖分 + 线段树处理就可以了. 代码: #include<iostream> #include<sstream> #include<map> #include<cmath> #include<fstream> #include<queue> #incl

训练指南 UVA - 11354(最小生成树 + 倍增LCA)

layout: post title: 训练指南 UVA - 11354(最小生成树 + 倍增LCA) author: "luowentaoaa" catalog: true mathjax: true tags: - 最小生成树 - LCA - 图论 - 训练指南 Bond UVA - 11354 题意 给你一张无向图,然后有若干组询问,让你输出a->b的最小瓶颈路 题解 先求出最小生成树,然后对这个最小生成树做LCA. #include<bits/stdc++.h>

UVA 11354 - Bond(树链剖分)

UVA 11354 - Bond 题目链接 题意:给定一个图,要求每次询问两点,求出这两点间路径最大危险系数最小 思路:先求最小生成树,在生成树上每次询问求LCT就可以了,利用树链剖分求解 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define lson(x) ((x<<1)+1) #d

uva 11354 - Bond(树链剖分)

题目链接:uva 11354 - Bond 题目大意:给定一张图,每次询问两个节点路径上进过边的危险值的最大值的最小值. 解题思路:首先建立最小生成数,然后根据这棵树做树链剖分. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int maxn = 50005; const int INF = 0x3f

HDU 4081Qin Shi Huang&amp;#39;s National Road System(最小生成树+最小瓶颈路)

 题意:秦始皇要修路.把N个城市用N-1条边连通.且他希望花费最小,可是这时候有一个多管闲事的道士出来说他有魔法能够帮助秦始皇变成一条路.可是仅仅能变出一条. 可是.两个人对修路的法案存在歧义,道士希望修路能够给很多其它的百姓带来福利.而秦始皇希望修路要尽量使花费小.最后,秦始皇拿出了一个公式A/B.A表示两个城市的人数,B表示出了用魔法变出来的路外.最短的总距离. 如今要你求出A/B的最大值. 思路:枚举连接哪两个城市.由于这条边是免费的.我们要求算上这条边的最小生成树.假设每次都求一次最

UVA 11354 Bond 瓶颈路 最小生成树+LCA类似

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 下面m行是(u,v) 和边权 下面q个询问 (u, v) 在这两个点间找一条路径使得这个路径上最大的边权最小. 数据保证询问的2个点之间一定存在路径 思路: 求瓶颈路,最小生成树跑一下. 然后求lca的代码里加入边权. 因为要使得最大的边权最小,所以用最小生成树的krusal算法, 正确性证明: 我们现在有联通块G,一个孤立点u,以及G与u之间的一些边,则显然我们选择边权最小的一条边把2个联通块连接. 这个过程就是krusal. #inc