洛谷T1967 货车运输 Kruskal最大生成树倍增LCA
这题的题意是:对于每组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相关推荐
- NOIP2013D1T3货车运输(最大生成树+倍增lca)
传送门 这道题,先用kruskal求一遍图中的最大生成树. 然后,倍增求lca,求lca的同时求出边权的最小值. #include <cstring> #include <cstdi ...
- 洛谷1967 火车运输 kruskal求最大生成树 倍增LCA维护最小值
传送门 其实NOIP某些年的第三题也并不是很难嘛... 题目分析: 题目中要求求出某两点之间可以运输的最大重量,也就是这两个点的某条路径上边权最小的边的权值的最大值 很显然,题目中的运输最大重量与选择 ...
- 【杂题总汇】NOIP2013(洛谷P1967) 货车运输
[洛谷P1967] 货车运输 重做NOIP提高组ing... +传送门-洛谷P1967+ ◇ 题目(copy from 洛谷) 题目描述 A国有n座城市,编号从1到n,城市之间有m条双向道路.每一条道 ...
- noip 2013 洛谷 P1967 货车运输
题目:货车运输 大致题意: 给出一张无向带权图,对于m个询问(X,Y),要求找出X到Y的一条路径使得路径上的最小边权最大,并输出这个最小边权. 思路: 可以看出,X到Y的满足条件的路径一定在原图的最大 ...
- 洛谷1967货车运输
题目:https://www.luogu.org/problemnew/show/P1967 倍增LCA裸题.用了在线.还有离线O(n)做法.树链剖分做法,暂不管了. (自己程序的)坑点:1.xnt从 ...
- 洛谷 P1967货车运输 并查集+贪心 不需要用LCA!
题目链接 题目链接 题解 要求所有的路径中最小边长的最大值! 我们贪心的加边,依照边从大往小的方式往里添加,然后合并并查集. 每次当查询分布在两个待合并的并查集的时候,当前的边长就是这次查询的答案. ...
- 洛谷 P4281 [AHOI2008]紧急集合 / 聚会(树上倍增 LCA)
[AHOI2008]紧急集合 / 聚会 题目描述 欢乐岛上有个非常好玩的游戏,叫做"紧急集合".在岛上分散有 n n n 个等待点,有 n − 1 n-1 n−1 条道路连接着它们 ...
- 洛古1967 货车运输
具体思路: 最大生成树 + 倍增LCA 首先感谢tqc大佬为我的耐心修改代码(你可能是改了个shi- -) 贴代码 include include include include include us ...
- 货车运输题解 最大生成树+lca
3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条 ...
最新文章
- PNAS:微生物组互作塑造宿主适应度
- Chrome插件开发进阶
- php去掉字符串的最后一个字符
- Linux查看文件夹大小的命令
- PPT(五)-让你的图片靓起来!
- MATLAB R2014a 中文版下载安装图文教程
- 什么样的人适合自学编程?你以为你自学难是为什么?来看看答案吧!
- filepermission java,Java FilePermission getActions()方法与示例
- Vue.js(学习Vue3之前必须要掌握的知识)
- 自动化测试 短信验证登录
- linux系统开启端口命令
- 手机游戏之Jad文件及MANIFEST.MF文件
- 有哪些好用的word文件对比工具
- python 入门篇 之 正则表达式re.findall的使用
- 二层交换机 三层交换机 四层交换机的区别
- 后端——》Java程序推送微信订阅消息
- CBinsight重磅报告 | 如何从谷歌亚马逊苹果微软脸书的9年专利之争,看5大巨头在AI行业的未来10年之争
- 用UltraISO制作Ubuntu_18.04U盘启动盘
- java判断是否为long_java怎么判断是否是Long类型
- pic18f66k80_boot 与 led (hex)
热门文章
- 多进程event通信
- Linux 虚拟机配置-network is unreachable
- rebuild myself rebuild my world
- 必须要知道Java如何取得当前路径
- Arcpy报错及解决——持续补充中
- mysql 建立索引更慢_如何运用“提前发布,经常发布”来建立更好的品牌
- 什么是 devops_DevOps对您意味着什么?
- 前端:HTML/05/lt;meta标记,XHTML简介及其编写规范,表格标签(lt;table)及其相关标签(lt;tr,lt;td或lt;th)
- Git笔记(22) 项目贡献要点
- 深度学习笔记(18) 迁移学习