Luogu1967 NOIP2013 货车运输 最大生成树、倍增

传送门

题意:给出一个$N$个节点、$M$条边的图,$Q$次询问,每一次询问两个点之间的所有可行路径中经过的边的边权的最小值中的最大值。$N \leq 10000 , M \leq 50000 , Q \leq 30000$


很套路的题目,没什么好说的,最大生成树上倍增求一段以内的最短边,然后每一次询问跳$LCA$即可。

注意:图可能是不连通的,所以在跳$LCA$之前要判断一下是否在一个连通块内。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 inline int read(){
 4     int a = 0;
 5     char c = getchar();
 6     while(!isdigit(c))  c = getchar();
 7     while(isdigit(c))   a = (a << 3) + (a << 1) + (c ^ '0') , c = getchar();
 8     return a;
 9 } 
10 vector < int > tree[10001] , w[10001];
11 int pro[30001][3] , head , depth[10001] , father[10001] , dad[10001] , wei[10001];
12 struct Edge{
13     int start , end , w;
14 }Ed[50001];
15 bool cmpforEdge(Edge a , Edge b){return a.w > b.w;}
16 int find(int a){return father[a] == a ? a : (father[a] = find(father[a]));}
17 inline int min(int a , int b){return a < b ? a : b;}
18 void LCA(int t , int pa){
19     depth[t] = depth[dad[t] = pa] + 1;
20     for(int i = 0 ; i < tree[t].size() ; i++)
21         if(!depth[tree[t][i]]){
22             wei[tree[t][i]] = w[t][i];
23             LCA(tree[t][i] , t);
24         }
25 }
26 inline int goLCA(int a , int b){
27     int minN = 100001;
28     while(a != b)
29         if(depth[a] > depth[b]){
30             minN = min(minN , wei[a]);
31             a = dad[a];
32         }
33         else{
34             minN = min(minN , wei[b]);
35             b = dad[b];
36         }
37     return minN;
38 }
39 int main(){
40     int N = read() , M = read();
41     for(int i = 1 ; i <= N ; i++)   father[i] = i;
42     for(int i = 0 ; i < M ; i++)
43         Ed[i].start = read() , Ed[i].end = read() , Ed[i].w = read();
44     sort(Ed , Ed + M , cmpforEdge);
45     for(int i = 0 ; i < M ; i++)
46         if(find(Ed[i].start) - find(Ed[i].end)){
47             father[find(Ed[i].start)] = find(Ed[i].end);
48             tree[Ed[i].start].push_back(Ed[i].end);
49             tree[Ed[i].end].push_back(Ed[i].start);
50             w[Ed[i].start].push_back(Ed[i].w);
51             w[Ed[i].end].push_back(Ed[i].w);
52         }
53     int num = read();
54     for(int i = 0 ; i < num ; i++)  pro[i][0] = read() , pro[i][1] = read();
55     for(int i = 1 ; i <= N ; i++)
56         if(!depth[i]){
57             head = 0;
58             LCA(i , 0);
59             for(int j = 0 ; j < num ; j++)
60                 if(!pro[j][2])
61                     if(find(pro[j][0]) == find(i) && find(pro[j][1]) == find(i))
62                         pro[j][2] = goLCA(pro[j][0] , pro[j][1]);
63                     else    if(find(pro[j][0]) == find(i) || find(pro[j][1]) == find(i))
64                         pro[j][2] = -1;
65         }
66     for(int i = 0 ; i < num ; i++)  printf("%d\n" , pro[i][2]);
67     return 0;
68 }

转载于:https://www.cnblogs.com/Itst/p/9852989.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值