传送门

文章目录

  • 题目描述
  • 题目解析
  • 代码

题目描述

题目解析

本题如果告诉你,城市形成了一棵树,是不是就迎刃而解了呢?
本题的关键就是把稠密图转化为一片森林(就是可能有很多棵树啦)
怎么转化呢?
考虑哪些边是没用的
如果AB已经可以联通且限重很大,再给我一条A到B限重很小的边肯定没有用了
换句话说,我们有用的边就是本图中的一座最大生成森林
(不明白这个词的童鞋可以类比一下最小生成树的概念)

怎么证明呢?
很容易
考虑怎么生成最大森林的:
每次选出未选的权值最大的边,如果两边的点未联通就连上

假设A到B的最好路径有一条边X不在这个森林上
那么这条边的权值肯定大于森林上AB路径的最小值Y(这样森林上的路径才不是最优的)
那么我们建造森林时肯定会使X在Y之前枚举到
而此时AB不连通(因为枚举到Y时还不连通)
那么应该把X加入森林中
和“X不在这个森林上"矛盾
证完啦(自己写的证明,可能有些草率 )

转化为树上问题后就非常简单
倍增,dfs序,树剖,都可以啦(还有很多做法但我还不会。。。)
联通判断常规并查集就OK了
说起来还是倍增好写
那就写倍增啦

倍增第一次少取了一个min还挂掉了。。。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mid ((l+r)>>1)
#define ls k<<1
#define rs k<<1|1
const int N=2e5+100;
const int M=2e4+100;int n,m,q;
int a,b,c;struct node{int to,nxt,v;
}p[N];
int fi[N],cnt=-1;
void addline(int x,int y,int v){//  printf("addline:x=%d y=%d v=%d\n",x,y,v);p[++cnt]=(node){y,fi[x],v};fi[x]=cnt;
}int fa[N];
int find(int x){return fa[x]==x ? x : fa[x]=find(fa[x]);}
void merge(int a,int b){int aa=find(a),bb=find(b);fa[aa]=bb;
}int dep[N],f[N],up[N];
void dfs(int x,int ffa){f[x]=ffa;dep[x]=dep[ffa]+1;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==ffa) continue;up[to]=p[i].v;dfs(to,x);}return;
} struct node2{int x,y,v;bool operator < (const node2 o)const {return v>o.v;}
}e[N];struct node3{int pl,mn;
}dp[M][20];
int mi[20];
void solve(){mi[0]=1;for(int i=1;i<=16;i++) mi[i]=mi[i-1]<<1;for(int i=1;i<=n;i++){dp[i][0].pl=f[i];dp[i][0].mn=up[i];
//      printf("ok i=%d k=0 pl=%d mn=%d\n",i,dp[i][0].pl,dp[i][0].mn);}for(int k=1;k<=15;k++){for(int i=1;i<=n;i++){if(dep[i]>=mi[k]){dp[i][k].pl=dp[dp[i][k-1].pl][k-1].pl;dp[i][k].mn=min(dp[i][k-1].mn,dp[dp[i][k-1].pl][k-1].mn);
//              printf("i=%d k=%d pl=%d mn=%d\n",i,k,dp[i][k].pl,dp[i][k].mn);}}}
}int lca(int x,int y){int ans=2e9;if(dep[y]>dep[x]) swap(x,y);for(int k=15;k>=0;k--){if(dep[x]-mi[k]<dep[y]) continue;ans=min(ans,dp[x][k].mn);x=dp[x][k].pl;
//      printf("ok x=%d y=%d ans=%d\n",x,y,ans);}for(int k=15;k>=0;k--){if(mi[k]>dep[x]) continue;if(dp[x][k].pl==dp[y][k].pl) continue;ans=min(ans,dp[x][k].mn);x=dp[x][k].pl;ans=min(ans,dp[y][k].mn);y=dp[y][k].pl;
//      printf("x=%d y=%d ans=%d\n",x,y,ans);}if(x!=y) ans=min(ans,min(dp[y][0].mn,dp[x][0].mn));//这里x和y的dp都要考虑取min,显然不一样啊!!!return ans;
}int main(){memset(fi,-1,sizeof(fi));memset(dep,-1,sizeof(dep));scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) fa[i]=i;for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v);sort(e+1,e+1+m);for(int i=1;i<=m;i++){int xx=find(e[i].x),yy=find(e[i].y);if(xx==yy) continue;merge(xx,yy);addline(e[i].x,e[i].y,e[i].v);addline(e[i].y,e[i].x,e[i].v);}for(int i=1;i<=n;i++){if(dep[i]==-1){dep[i]=0;dfs(i,0);}}solve();scanf("%d",&q);for(int i=1;i<=q;i++){scanf("%d%d",&a,&b);if(find(a)!=find(b)) printf("-1\n");else printf("%d\n",lca(a,b));}return 0;
}
/*
11 9
1 2 8
1 3 15
1 7 7
2 4 12
3 6 9
3 5 6
8 9 11
8 10 10
10 11 15
100
*/

货车运输(洛谷P1967)(倍增)相关推荐

  1. [最大生成树Kruskal/倍增LCA] 火车运输 洛谷P1967

    题目描述 AA 国有 nn 座城市,编号从 11 到 nn ,城市之间有 mm 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重 ...

  2. 【题解】【洛谷 P1967】 货车运输

    目录 洛谷 P1967 货车运输 原题 题解 思路 代码 洛谷 P1967 货车运输 原题 题面请查看洛谷 P1967 货车运输. 题解 思路 根据题面,假设我们有一个普通的图: 作图工具:Graph ...

  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. 【洛谷P1967】[NOIP2013]货车运输

    货车运输 题目链接 显然,从一点走到另一点的路径中,最小值最大的路径一定在它的最大生成树上 所以要先求出最大生成树,再在生成树上找最近公共祖先,同时求出最小值. 1 #include<iostr ...

  6. 洛谷 P1967 Vijos P1843 CODE[VS] P3287 [NOIP2013 D1T3] 货车运输

    题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多 ...

  7. 洛谷T1967 货车运输 Kruskal最大生成树倍增LCA

    这题的题意是:对于每组x.y,求x到y路径上最小边权的最大值. 于是可以使用最大生成树,因为最大生成树满足性质:生成树中最小边权最大,且任意两点间路径上最小边权最大. 有了树之后,要求路径,那就要考虑 ...

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

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

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

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

最新文章

  1. R语言gganimate包创建可视化gif动图、并使用anim_save函数保存可视化gif动图(gganimate export to gif)
  2. php时间戳 今天昨天,php求今天、昨天、明天时间戳的简单实现方法
  3. java 求最长子串
  4. C++ Lists(链表)
  5. amd cpu排行_最新AMD CPU排行出炉 E6版3000+夺魁
  6. 如何订阅MQTT服务器历史消息,MQTT协议之消息订阅
  7. 蓝牙怎么区分单模和双模_小院闲聊#01#——蓝牙的发展和不同蓝牙之间的关系...
  8. shell脚本获取mysql插入数据自增长id的值
  9. validationEngine中文版 — jquery强大的表单验证插件,留着以后会用得上
  10. 羽毛球:东南大学vs南京大学
  11. 小程序UI库 iView Weapp
  12. TTL与CMOS电路
  13. native2ascii.exe详细使用方法、native2ascii转换示例
  14. 吉林省吉林市谷歌高清卫星地图下载(百度网盘离线包下载)
  15. Zetero+zotfile+坚果云配置
  16. 方差、标准差、均方差、均方根值(RMS)、均方根误差(RMSE)
  17. git 创库命令使用
  18. python代码使用cython进行加密
  19. HA+LVS 高可用集群
  20. 2to3:python2自动转python3

热门文章

  1. 逻辑回归算法背后的数学
  2. linux运行.pak文件,使用game-to-flatpak脚本将商业Linux游戏安装程序转换为Flatpak应用程序...
  3. st link v2引脚连接_ST-Link资料02_ST-Link固件介绍,及固件命名规则
  4. Java开发之上班摸鱼!写最少的代码!
  5. 安卓平板运行python_使用Python进行手机平板移动开发 | 学步园
  6. 怎么删除mysql的所有文件内容_mysql删除全部数据库
  7. JAVA中的GridView每一个赋值,在ASP.NET 2.0中操作数据之六十二:GridView批量更新数据...
  8. 岛屿类问题的广度优先深度优先双解法(Leetcode题解-Python语言)
  9. 提升对前端的认知,不得不了解Web API的DOM和BOM
  10. 高等数学下-赵立军-北京大学出版社-题解-练习8.2