这题的题意是:对于每组x、y,求x到y路径上最小边权的最大值。

于是可以使用最大生成树,因为最大生成树满足性质:生成树中最小边权最大,且任意两点间路径上最小边权最大。

有了树之后,要求路径,那就要考虑LCA。

首先,这题可以树剖,但是我太懒了,于是写了倍增233

具体搞法:

Kruskal跑出最大生成树,然后在树上倍增LCA,处理出2个数组:fa[][]和minv[][];fa[][]表示第2^k个父亲是谁,minv[][]表示当前节点到其第2^k个父亲的路径上的最小边权。对于每次查询,在求LCA的同时,沿路将各段的minv取并即可,每次时间与LCA查询相同,为logn。

现在还有一个问题:图不一定是连通的。。。不能无脑LCA。。。

解决这个问题的方法是:在Kruskal结束后,对并查集中的每个集合各进行一次LCA预处理。对于每次查询,先判断两节点是否属于同一集合,若属于同一集合则进行LCA查询,否则直接输出-1。

代码如下:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<ctime>
  6 #include<cstdlib>
  7
  8 #include<string>
  9 #include<stack>
 10 #include<queue>
 11 #include<vector>
 12 #include<algorithm>
 13 #include<map>
 14 #include<set>
 15
 16 #define inf 2147483647
 17 #define ri register int
 18 #define ll long long
 19
 20 using namespace std;
 21
 22 inline void read(int &x){
 23     x=0;
 24     char t=getchar();
 25     bool f=0;
 26
 27     while(t<'0' || t>'9'){
 28         if(t=='-')f=1;
 29         t=getchar();
 30     }
 31
 32     while(t>='0' && t<='9'){
 33         x=(x<<3)+(x<<1)+t-'0';
 34         t=getchar();
 35     }
 36
 37     if(f)x=-x;
 38 }
 39
 40 inline void addedge(int,int,int);
 41 int u[100010];
 42 int v[100010];
 43 int w[100010];
 44 int first[10005];
 45 int next[100010];
 46 int pe=0;  //邻接表(无向)
 47
 48 inline bool cmp(const int a,const int b);
 49 int ha_e[50005];  //边排序辅助数组
 50
 51 inline void Kruskal();
 52 int find(int);
 53 int bcj[10005];  //并查集
 54 bool use[50005];  //记录边是否使用
 55
 56 void dfs(int,int);  //LCA预处理,直接父亲及最小边权在上层处理
 57 bool vis[10005];  //防止重复访问
 58 int dep[10005];  //节点深度
 59 int fa[10005][15];  //LCA表
 60 int minv[10005][15];  //节点到其第2^k个父亲路径间的最小边权
 61
 62 inline int query(int,int);  //查询路径最小边权
 63
 64 int n,m,q;
 65 int rest;
 66 int x,y,z;
 67
 68 int main(){
 69     read(n);read(m);
 70     rest=n;
 71
 72     for(ri i=1;i<=m;i++){
 73         read(x);read(y);read(z);
 74
 75         addedge(x,y,z);
 76         addedge(y,x,z);
 77
 78         ha_e[i]=i<<1;
 79     }  //建初始图
 80
 81     sort(ha_e+1,ha_e+1+m,cmp);  //边权从大到小排序
 82     Kruskal();  //生成最大生成树,记录需要使用的边
 83
 84     memset(vis,0,sizeof(vis));
 85
 86     for(ri i=1;i<=n;i++)  //生成2个倍增表
 87         if(!vis[find(i)]){
 88             fa[i][0]=0;  //根节点无父亲
 89             minv[i][0]=inf;
 90             dfs(i,1);  //以i号节点为根进行遍历
 91         }
 92
 93     read(q);
 94
 95     for(ri i=1;i<=q;i++){
 96         read(x);read(y);
 97
 98         if(find(x)!=find(y)){
 99             printf("-1\n");
100             continue;
101         }
102
103         if(dep[x]>dep[y])swap(x,y);  //使y更深
104
105         printf("%d\n",query(x,y));
106     }
107
108     return 0;
109 }
110
111 inline void addedge(int x,int y,int z){
112     pe++;
113     u[pe]=x;
114     v[pe]=y;
115     w[pe]=z;
116     next[pe]=first[x];
117     first[x]=pe;
118 }
119
120 inline bool cmp(const int a,const int b){
121     return w[a]>w[b];
122 }
123
124 int find(int x){
125     if(bcj[x]==x)return x;
126     else return bcj[x]=find(bcj[x]);
127 }
128
129 inline void Kruskal(){
130     int x,y,fx,fy;
131
132     for(ri i=1;i<=n;i++)bcj[i]=i;
133     memset(use,0,sizeof(use));
134
135     for(ri i=1;i<=m && rest>1;i++){
136         x=u[ha_e[i]];
137         y=v[ha_e[i]];
138         fx=find(x);
139         fy=find(y);
140
141         if(fx!=fy){
142             bcj[fx]=fy;
143             rest--;
144             use[ha_e[i]>>1]=1;
145         }
146     }
147 }
148
149 void dfs(int s,int h){
150     int e,t;
151
152     dep[s]=h;
153     vis[s]=1;
154
155     for(ri i=1;(1<<i)<h;i++){  //i=0已在上层处理;若1<<i==h则恰有一个节点越界
156         fa[s][i]=fa[fa[s][i-1]][i-1];
157         minv[s][i]=min(minv[s][i-1],minv[fa[s][i-1]][i-1]);
158     }
159
160     e=first[s];
161     t=v[e];
162
163     while(e){
164         if(!vis[t] && use[(e+1)>>1]){
165             fa[t][0]=s;
166             minv[t][0]=w[e];
167             dfs(t,h+1);
168         }
169
170         e=next[e];
171         t=v[e];
172     }
173 }
174
175 inline int query(int x,int y){
176     int dt=dep[y]-dep[x];
177     int ans=inf;
178
179     for(ri i=0;(1<<i)<=dt;i++)
180         if((1<<i)&dt){
181             ans=min(ans,minv[y][i]);
182             y=fa[y][i];
183         }
184
185     if(x==y)return ans;
186
187     for(ri i=13;i>=0;i--)
188         if(fa[x][i]!=fa[y][i]){
189             ans=min(ans,minv[x][i]);
190             ans=min(ans,minv[y][i]);
191
192             x=fa[x][i];
193             y=fa[y][i];
194         }
195
196     ans=min(ans,minv[x][0]);
197     ans=min(ans,minv[y][0]);
198
199     return ans;
200 }

转载于:https://www.cnblogs.com/running-coder-wfh/p/7765685.html

洛谷T1967 货车运输 Kruskal最大生成树倍增LCA相关推荐

  1. NOIP2013D1T3货车运输(最大生成树+倍增lca)

    传送门 这道题,先用kruskal求一遍图中的最大生成树. 然后,倍增求lca,求lca的同时求出边权的最小值. #include <cstring> #include <cstdi ...

  2. 洛谷1967 火车运输 kruskal求最大生成树 倍增LCA维护最小值

    传送门 其实NOIP某些年的第三题也并不是很难嘛... 题目分析: 题目中要求求出某两点之间可以运输的最大重量,也就是这两个点的某条路径上边权最小的边的权值的最大值 很显然,题目中的运输最大重量与选择 ...

  3. 【杂题总汇】NOIP2013(洛谷P1967) 货车运输

    [洛谷P1967] 货车运输 重做NOIP提高组ing... +传送门-洛谷P1967+ ◇ 题目(copy from 洛谷) 题目描述 A国有n座城市,编号从1到n,城市之间有m条双向道路.每一条道 ...

  4. noip 2013 洛谷 P1967 货车运输

    题目:货车运输 大致题意: 给出一张无向带权图,对于m个询问(X,Y),要求找出X到Y的一条路径使得路径上的最小边权最大,并输出这个最小边权. 思路: 可以看出,X到Y的满足条件的路径一定在原图的最大 ...

  5. 洛谷1967货车运输

    题目:https://www.luogu.org/problemnew/show/P1967 倍增LCA裸题.用了在线.还有离线O(n)做法.树链剖分做法,暂不管了. (自己程序的)坑点:1.xnt从 ...

  6. 洛谷 P1967货车运输 并查集+贪心 不需要用LCA!

    题目链接 题目链接 题解 要求所有的路径中最小边长的最大值! 我们贪心的加边,依照边从大往小的方式往里添加,然后合并并查集. 每次当查询分布在两个待合并的并查集的时候,当前的边长就是这次查询的答案. ...

  7. 洛谷 P4281 [AHOI2008]紧急集合 / 聚会(树上倍增 LCA)

    [AHOI2008]紧急集合 / 聚会 题目描述 欢乐岛上有个非常好玩的游戏,叫做"紧急集合".在岛上分散有 n n n 个等待点,有 n − 1 n-1 n−1 条道路连接着它们 ...

  8. 洛古1967 货车运输

    具体思路: 最大生成树 + 倍增LCA 首先感谢tqc大佬为我的耐心修改代码(你可能是改了个shi- -) 贴代码 include include include include include us ...

  9. 货车运输题解 最大生成树+lca

    3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条 ...

最新文章

  1. PNAS:微生物组互作塑造宿主适应度
  2. Chrome插件开发进阶
  3. php去掉字符串的最后一个字符
  4. Linux查看文件夹大小的命令
  5. PPT(五)-让你的图片靓起来!
  6. MATLAB R2014a 中文版下载安装图文教程
  7. 什么样的人适合自学编程?你以为你自学难是为什么?来看看答案吧!
  8. filepermission java,Java FilePermission getActions()方法与示例
  9. Vue.js(学习Vue3之前必须要掌握的知识)
  10. 自动化测试 短信验证登录
  11. linux系统开启端口命令
  12. 手机游戏之Jad文件及MANIFEST.MF文件
  13. 有哪些好用的word文件对比工具
  14. python 入门篇 之 正则表达式re.findall的使用
  15. 二层交换机 三层交换机 四层交换机的区别
  16. 后端——》Java程序推送微信订阅消息
  17. CBinsight重磅报告 | 如何从谷歌亚马逊苹果微软脸书的9年专利之争,看5大巨头在AI行业的未来10年之争
  18. 用UltraISO制作Ubuntu_18.04U盘启动盘
  19. java判断是否为long_java怎么判断是否是Long类型
  20. pic18f66k80_boot 与 led (hex)

热门文章

  1. 多进程event通信
  2. Linux 虚拟机配置-network is unreachable
  3. rebuild myself rebuild my world
  4. 必须要知道Java如何取得当前路径
  5. Arcpy报错及解决——持续补充中
  6. mysql 建立索引更慢_如何运用“提前发布,经常发布”来建立更好的品牌
  7. 什么是 devops_DevOps对您意味着什么?
  8. 前端:HTML/05/lt;meta标记,XHTML简介及其编写规范,表格标签(lt;table)及其相关标签(lt;tr,lt;td或lt;th)
  9. Git笔记(22) 项目贡献要点
  10. 深度学习笔记(18) 迁移学习