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 ...
随机推荐
- ios取证
摘录自:<IOS取证实战> Andrew Hoog著 viaForensics公司,今年已经募集到1600万创业基金 2007-2011年初,AT&T是在美国唯一为iphone提供 ...
- Codeforces Beta Round #62 题解【ABCD】
Codeforces Beta Round #62 A Irrational problem 题意 f(x) = x mod p1 mod p2 mod p3 mod p4 问你[a,b]中有多少个数 ...
- Android自定义Seekbar拖动条式样
SeekBar拖动条可以由用户控制,进行拖动操作.比如,应用程序中用户需要对音量进行控制,就可以使用拖动条来实现. 1.SeekBar控件的使用 1.1SeekBar常用属性 SeekBar的常用属性 ...
- JS区别不同浏览器(微信、手机等)
最近一直在忙于自己公司的旅游产品,设计方面太广并且要兼容各种设备和场景,包括PC.Mobile.Pad.还有各种支付.由于微信支付和支付宝存在竞争,所以需要区别不同的浏览器,并且WEB项目还要出现在A ...
- Android 5.0 双卡信息管理分析
首先,如前面的博文所讲的,Android5.0开始支持双卡了.另外,对于双卡的卡信息的管理,也有了实现,尽管还不是完全彻底完整,如卡的slot id, display name,iccid,color ...
- Ubunbu新建的用户使用SecureCrt无法Table补全、无法高亮
Check 两个地方: 1. 确保/etc/passwd中配置有/bin/bash (这个是用来控制补全). 2. 在~/.bashrc中配置, export TERM=linux (这个是用来控制 ...
- whoami 和 Who am i
① 两个命令在一般的情况下,似乎效果是一样的 ② 但是当你执行完su 命令切换用户后,就不一样了,who am i 显示最早login的账户,而whoami 显示切换后的账户 例如: -bash-3. ...
- vue开发资料
http://cn.vuejs.org/v2/guide/ (vue框架手册)https://router.vuejs.org/zh-cn/ (vue框架路由手册)https://github.com ...
- [Core Javascirpt] Basic Metaprogramming: Dynamic Method
Somehow it looks like reflect in Java. For example: We define an mothod on the Object, it called def ...
- Hadoop - Kylin On OLAP
1.概述 Apache Kylin是一个开源的分布式分析引擎,提供SQL接口并且用于OLAP业务于Hadoop的大数据集上,该项目由eBay贡献于Apache. 2.What is Kylin 在使用 ...