BZOJ3732 解析报告//LCA,最小生成树
3732: Network
题目描述
给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。
图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000).
现在有 K个询问 (1 < = K < = 15,000)。
每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?
输入
第一行: N, M, K。
第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。
第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?
输出
对每个询问,输出最长的边最小值是多少。
样例输入
1 2 5
2 3 4
3 4 3
1 4 8
2 5 7
4 6 2
1 2
1 3
1 4
2 3
2 4
5 1
6 2
6 1
样例输出
5
5
4
4
7
4
5
提示
1 <= N <= 15,000 1 <= M <= 30,000 1 <= d_j <= 1,000,000,000 1 <= K <= 15,000
分析:
拿到这道题我们会有思考。什么是最长的边的最小值。这也正是这道题的突破口。在一个图中任意两点都有很多条路,我们要找出其中一条路,使这条路上的最大的权值是其他路上最大权值中最小的。而我们要保证权值最小,但是还是当前路上最大。由于这里没有限制边数,我们会想到。树上的一个有趣的模型——最小生成树。这棵树上每条路都是整个图中较小的边,而我们的问题就转化成了在最小生成树上找最大边。这个时候就可以用倍增的思想找LCA。在一棵树上两点之间最短距离一定经过它们的LCA。所以我们找出2点的LCA而且维护这条最短路径上的最大边即可。
为什么两点之间的最长边的最小值一定在这个图上的最小生成树上呢?
假设我们有一个这样的无向图。
![]() |
![]() |
![]() |
1,这是一个很普通的无向图。首先我们先找出它的最小生成树。一种贪婪策略。嗯就是这样。
2,其次我们找3号点和4号点中最长边的最大值是2.这个边在最小生成树上。
3,我们假设一个边4-3这条边的权值假设成1.而我们发现当这个边权都比最小生成树上的边的权值还小,说明这条边一定在最小生成树上。如图所示。
所以:这道题其实就是。首先,建最小生成树,其次找LCA维护最值。之后。提交。AC。
#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
struct node{
int x,y,val;
}point[100010];
struct node_1{
int num,minval;
}f[21][100010];
struct node_2{
int v,next,val;
}edge[1000010];
int head[1000010],cnt;
int cmp(node a,node b)
{
return a.val<b.val;
}
int visit[100010],father[100010],n,m,q,dep[100000];
int find_father(int x)
{
return father[x]==x ? x : father[x]=find_father(father[x]);
}
void add(int x,int y,int val)
{
edge[++cnt]=(node_2){y,head[x],val};
head[x]=cnt;
edge[++cnt]=(node_2){x,head[y],val};
head[y]=cnt;
return ;
}
void dfs(int x,int step)
{
visit[x]=1;
dep[x]=step;
for(int i=head[x];i!=-1;i=edge[i].next)
{
if(visit[edge[i].v])continue;
f[0][edge[i].v].num=x;
f[0][edge[i].v].minval=edge[i].val;
dfs(edge[i].v,step+1);
}
return ;
}
int LCA(int x,int y)
{
int lca=-1;
if(dep[x]>dep[y])swap(x,y);
for(int i=20;~i;--i)
{
if(dep[f[i][y].num]>=dep[x])
{
lca=max(lca,f[i][y].minval);
y=f[i][y].num;
}
}
if(x==y)return lca;
for(int i=20;~i;--i)
{
if(f[i][y].num!=f[i][x].num)
{
lca=max(lca,max(f[i][y].minval,f[i][x].minval));
y=f[i][y].num;
x=f[i][x].num;
}
}
lca=max(lca,max(f[0][y].minval,f[0][x].minval));
return lca;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&m,&q);
int a,b,c;
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&a,&b,&c);
point[i].x=a;point[i].y=b;point[i].val=c;
}
sort(point+1,point+1+m,cmp);
int cnt_1=0;
for(int i=1;i<=n;++i)father[i]=i;
for(int i=1;i<=m;++i)
{
int la = find_father(point[i].x),lb = find_father(point[i].y);
if(la!=lb)
{
father[lb]=la;
add(point[i].x,point[i].y,point[i].val);
++cnt_1;
}
if(cnt_1==n-1)break;
}
f[0][cnt_1/2].num=cnt_1/2;f[0][cnt_1/2].minval=0;
dfs(cnt_1/2,1);
for(int i=1;i<=20;++i)
for(int j=1;j<=n;++j)
{
f[i][j].minval=max(f[i-1][j].minval,f[i-1][f[i-1][j].num].minval);
f[i][j].num=f[i-1][f[i-1][j].num].num;
}
for(int i=1;i<=q;++i)
{
scanf("%d%d",&a,&b);
printf("%d\n",LCA(a,b));
}
return 0;
}
嗯。就是这样。
BZOJ3732 解析报告//LCA,最小生成树的更多相关文章
- BZOJ3732Network——kruskal重构树+倍增+LCA/最小生成树+倍增
题目描述 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 & ...
- LCA&最小生成树
LCA 经常被用来使用.比如询问树两点之间的距离. 比如树上差分 都是经常被使用的类型.有的时候倍增求LCA的同时还可以优化算法. 这道题呢 求一个严格的最小生成树,当然如果不严格的话如果有重边那么就 ...
- uva11354 LCA+最小生成树+dp
源自大白书 题意 有n座城市通过m条双向道路相连,每条道路都有一个危险系数.你的任务是回答若干个询问,每个询问包含一个起点s和一个终点t,要求找到一条从s到t的路,使得途径所有的边的大最大危险系数最小 ...
- The Shortest Statement(Educational Codeforces Round 51 (Rated for Div.2)+最短路+LCA+最小生成树)
题目链接 传送门 题面 题意 给你一张有\(n\)个点\(m\)条边的联通图(其中\(m\leq n+20)\),\(q\)次查询,每次询问\(u\)与\(v\)之间的最短路. 思路 由于边数最多只比 ...
- 洛谷 P1967 货车运输 LCA + 最小生成树
两点之间边权最大值的最小值一定在图的最小生成树中取到. 求出最小生成树,进行倍增即可. Code: #include<cstdio> #include<algorithm> u ...
- OpenJudge 2990:符号三角形 解析报告
2990:符号三角形 总时间限制: 1000ms 内存限制: 65536kB 描述 符号三角形的第1行有n个由“+”和”-“组成的符号 ,以后每行符号比上行少1个,2个同号下面是”+“ ...
- BZOJ1088扫雷Mine 解析报告
1088: [SCOI2005]扫雷Mine Description 相信大家都玩过扫雷的游戏.那是在一个n*m的矩阵里面有一些雷,要你根据一些信息找出雷来.万圣节到了,“余”人国流行起了一种简单的扫 ...
- OpenJudge 2985数字组合 解析报告/DP
2985:数字组合 总时间限制: 1000ms 内存限制: 65536kB 描述 有n个正整数,找出其中和为t(t也是正整数)的可能的组合方式.如:n=5,5个数分别为1,2,3,4,5,t=5: ...
- openjudge7834:分成互质组 解析报告
7834:分成互质组 总时间限制: 1000ms 内存限制: 65536kB 描述 给定n个正整数,将它们分组,使得每组中任意两个数互质.至少要分成多少个组? 输入 第一行是一个正整数n.1 &l ...
随机推荐
- Jquery 实现input回车时跳转到下一个input元素
/** * 回车时跳转到下一个元素 * @Author HTL * @DateTime 2016-12-30T11:33:25+0800 * @param {[type]} $input [INP ...
- 每日英语:A Different Color: China's Chameleonic Politics
China has tried your form of government and found it wanting. That was the message delivered by Chin ...
- Enclosure POJ
0:Enclosure http://poj.openjudge.cn/challenge3/0/ 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 131072kB 描述 为了防止 ...
- Metaweblog在Android上使用
同步发表于http://avenwu.net/2015/02/04/metaweblog metaweblog是一个博客接口协议,目前主流的博客平台均支持该协议,比如博客园,CSDN,WordPres ...
- 如何导入大sql文件到虚拟主机mysql数据库
大部分网站虚拟主机为了安全起见,都限制了通过命令或者phpMyAdmin导入大sql文件到mysql数据库,例如godaddy只允许站长通过phpMyAdmin上传不超过2m的sql文件,但实际上我们 ...
- [原创]Java中的字符串比较,按照使用习惯进行比较
java中的字符串比较一般可以采用compareTo函数,如果a.compareTo(b)返回的是小于0的数,那么说明a的unicode编码值小于b的unicode编码值. 但是很多情况下,我们开发一 ...
- C#3.0新特性之扩展方法介绍
C#3.0扩展方法是给现有类型添加一个方法.现在类型即可是基本数据类型(如int,String等),也可以是自己定义的类.以下是引用片段: //Demo--1 //扩展基本类型 namespace T ...
- Jconsole加载Jtop插件
Jconsole加载Jtop插件http://automationqa.com/forum.php?mod=viewthread&tid=3719&fromuid=2
- jQuery超炫酷按钮插件及源码
现在大部分网页的按钮都是经过美化的,那些原始的浏览器按钮太过于枯燥乏味,让用户失去和网站交互的兴趣.早期我们都是通过背景图片来美化网页按钮,而现在我们可以利用扩展性更好的CSS3来制作漂亮的网页按钮, ...
- Android源码网站
https://mirrors.tuna.tsinghua.edu.cn/ https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/ https://mirror ...


