BZOJ 3732 Network 最小瓶颈路

题目大意:给出一个无向边,很多询问,问x,y两地之间的最长路最短是多少。

思路:乍一看好像是二分啊。的确这个题二分可以做,但是时间会慢很多,有的题直接就T掉(NOIP2013货车运输)。其实这个题的模型就是最小瓶颈路模型。解法就是把无向图变成一个最小生成树,然后两点之间的最长路就是满足题意的答案。

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 15010
#define INF 0x7f7f7f7f
using namespace std;

struct Complex{
	int x,y,len;

	bool operator <(const Complex &a)const {
		return len < a.len;
	}
	void Read() {
		scanf("%d%d%d",&x,&y,&len);
	}
}edge[MAX << 2];

int points,edges,asks;
int head[MAX],total;
int next[MAX << 1],length[MAX << 1],aim[MAX << 1];

int fa[MAX];

int deep[MAX];
int father[MAX][20],min_length[MAX][20];

void Pretreatment();
int Find(int x);

inline void Add(int x,int y,int len);

void DFS(int x,int last);
void SparseTable();

int GetLCA(int x,int y);

int main()
{
	cin >> points >> edges >> asks;
	Pretreatment();
	for(int i = 1;i <= edges; ++i)
		edge[i].Read();
	sort(edge + 1,edge + edges + 1);
	for(int i = 1;i <= edges; ++i) {
		int fx = Find(edge[i].x);
		int fy = Find(edge[i].y);
		if(fx != fy) {
			Add(edge[i].x,edge[i].y,edge[i].len);
			Add(edge[i].y,edge[i].x,edge[i].len);
			fa[fx] = fy;
		}
	}
	DFS(1,0);
	SparseTable();
	for(int x,y,i = 1;i <= asks; ++i) {
		scanf("%d%d",&x,&y);
		printf("%d\n",GetLCA(x,y));
	}
	return 0;
}

void Pretreatment()
{
	for(int i = 1;i <= points; ++i)
		fa[i] = i;
}

int Find(int x)
{
	if(fa[x] == x)	return x;
	return fa[x] = Find(fa[x]);
}

inline void Add(int x,int y,int len)
{
	next[++total] = head[x];
	aim[total] = y;
	length[total] = len;
	head[x] = total;
}

void DFS(int x,int last)
{
	deep[x] = deep[last] + 1;
	for(int i = head[x];i;i = next[i]) {
		if(aim[i] == last)	continue;
		father[aim[i]][0] = x;
		min_length[aim[i]][0] = length[i];
		DFS(aim[i],x);
	}
}

void SparseTable()
{
	for(int j = 1;j < 20; ++j)
		for(int i = 1;i <= points; ++i) {
			father[i][j] = father[father[i][j - 1]][j - 1];
			min_length[i][j] = max(min_length[i][j - 1],min_length[father[i][j - 1]][j - 1]);
		}
}

int GetLCA(int x,int y)
{
	int re = 0;
	if(deep[x] < deep[y])	swap(x,y);
	for(int i = 19;i >= 0; --i)
		if(deep[father[x][i]] >= deep[y]) {
			re = max(re,min_length[x][i]);
			x = father[x][i];
		}
	if(x == y)	return re;
	for(int i = 19;i >= 0; --i)
		if(father[x][i] != father[y][i]) {
			re = max(re,min_length[x][i]);
			re = max(re,min_length[y][i]);
			x = father[x][i];
			y = father[y][i];
		}
	re = max(re,min_length[x][0]);
	re = max(re,min_length[y][0]);
	return re;
}
时间: 2024-08-29 22:28:35

BZOJ 3732 Network 最小瓶颈路的相关文章

最小瓶颈路 Uva 534 Frogger

说明:关于Uva的题目,可以在vjudge上做的,不用到Uva(那个极其慢的)网站去做. 最小瓶颈路:找u到v的一条路径满足最大边权值尽量小 先求最小生成树,然后u到v的路径在树上是唯一的,答案就是这条路径. Uva 534 Frogger Time Limit: 3000MS 64bit IO Format: %lld & %llu Description Freddy Frog is sitting on a stone in the middle of a lake. Suddenly h

HDU 4081Qin Shi Huang&amp;#39;s National Road System(最小生成树+最小瓶颈路)

 题意:秦始皇要修路.把N个城市用N-1条边连通.且他希望花费最小,可是这时候有一个多管闲事的道士出来说他有魔法能够帮助秦始皇变成一条路.可是仅仅能变出一条. 可是.两个人对修路的法案存在歧义,道士希望修路能够给很多其它的百姓带来福利.而秦始皇希望修路要尽量使花费小.最后,秦始皇拿出了一个公式A/B.A表示两个城市的人数,B表示出了用魔法变出来的路外.最短的总距离. 如今要你求出A/B的最大值. 思路:枚举连接哪两个城市.由于这条边是免费的.我们要求算上这条边的最小生成树.假设每次都求一次最

UVALive 5713 Qin Shi Huang&#39;s National Road System秦始皇修路(MST,最小瓶颈路)

题意: 秦始皇要在n个城市之间修路,而徐福声可以用法术位秦始皇免费修1条路,每个城市还有人口数,现要求徐福声所修之路的两城市的人口数之和A尽量大,而使n个城市互通需要修的路长B尽量短,从而使得A/B最大.问A/B最大是多少?(1000个城市) 思路: 老徐可免费修得1条路,那么剩下最多也只需要修n-2条路了,这n-2条路要尽量挑短的,而老徐的那条无所谓长短,只要两城人口尽量多即可.这是没有什么贪心策略的,因为老徐所修之路会影响MST的权值之和的大小.穷举所有城市对要O(n*n),再求次MST需要

UVA 10457 - Magic Car(最小瓶颈路)

UVA 10457 - Magic Car 题目链接 题意:m条路,每条路上必须维持速度v,现在有一辆车,启动能量和结束能量为a, b,途中消耗能量为经过路径最大速度减去最小速度,现在每次循环给定起点终点,问最小能量花费 思路:最小瓶颈路,利用kruskal去搞 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 205; con

最小瓶颈路与次小生成树

简介: 最小生成树是图论里面一类经典问题,可以有很多种变形,其中最小瓶颈路和次小生成树就是两种比较经典的变形.最小瓶颈路就是在两个结点之间求一条最长边最短的路径,而次小生成树则是所有生成树中权值排名第二的生成树(可以和最小生成树相等).下面我们分别来看看这两个问题. 最小瓶颈路: 给定一个加权无向图,并给定无向图中两个结点u和v,求u到v的一条路径,使得路径上边的最大权值最小.这个问题可以稍微加强一下,即求很多对结点之间的最小瓶颈路. 无向图中,任意两个结点的最小瓶颈路肯定在最小生成树上.因此,

【UVA534】Frogger 最小瓶颈路

题目大意:给定一张 N 个点的完全图,求 1,2 号节点之间的一条最小瓶颈路. 题解:可知,最小瓶颈路一定存在于最小生成树(最小瓶颈树)中.因此,直接跑克鲁斯卡尔算法,当 1,2 号节点在同一个联通块时,即可停止算法,并输出答案即可. 代码如下 #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using n

BZOJ 3732 Network

2016.1.28 纪念我BZOJ第一题 Description 给你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点的所有路径中,最长的边最小值是多少? Input 第一行: N,

bzoj 3732: Network 树上两点边权最值

http://www.lydsy.com/JudgeOnline/problem.php?id=3732 首先想到,要使得最长边最短,应该尽量走最短的边,在MST上. 然后像LCA那样倍增娶个最大值 #include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; const int ma

BZOJ 3732 Network Kruskal+倍增LCA

题目大意:给定一个n个点m条边的无向连通图,k次询问两点之间所有路径中最长边的最小值 NOIP2013 货车运输,几乎就是原题...只不过最小边最大改成了最大边最小... 首先看到最大值最小第一反应二分答案 但是二分答案O(kmlogn)明显做不了 这里我们考虑最小生成树 先生成一棵最小生成树,然后每次询问利用倍增LCA求出路径上的最大权值即可 本蒟蒻居然把LCA写挂了... 而且样例还过了... 伤不起啊... 90%达成 剩下一道刷点啥呢... #include<cstdio> #incl