UVa 11354 Bond 最小生成树+LCA倍增

题目来源:UVa 11354 Bond

题意:n个点m条边的图 q次询问 找到一条从s到t的一条边 使所有边的最大危险系数最小

思路:使最大的危险系数尽量小 答案是最小生成树上的边 然后用LCA倍增法记录s和t到他们最近公共祖先的最大值

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 50010;
const int INF = 0x3f3f3f3f;
int anc[maxn][30], maxcost[maxn][30];
int fa[maxn], L[maxn], cost[maxn], vis[maxn], f[maxn];
int n, m;
int first[maxn], cnt;
struct edge
{
	int u, v, w, next;
}e[maxn*2], e2[maxn*8];

bool cmp(edge a, edge b)
{
	return a.w < b.w;
}

void AddEdge(int u, int v, int w)
{
	e2[cnt].v = v;
	e2[cnt].w = w;
	e2[cnt].next = first[u];
	first[u] = cnt++;
	e2[cnt].v = u;
	e2[cnt].w = w;
	e2[cnt].next = first[v];
	first[v] = cnt++;

}
void pre()
{
	for(int i = 1; i <= n; i++)
	{
		anc[i][0] = fa[i]; maxcost[i][0] = cost[i];
		for(int j = 1; (1<<j) < n; j++)
			anc[i][j] = -1;
	}
	for(int j = 1; (1<<j) < n; j++)
		for(int i = 1; i <= n; i++)
			if(anc[i][j-1] != -1)
			{
				int a = anc[i][j-1];
				anc[i][j] = anc[a][j-1];
				maxcost[i][j] = max(maxcost[i][j-1], maxcost[a][j-1]);
			}

}

int query(int p, int q)
{
	int tmp, log, i;
	if(L[p] < L[q])
		swap(p, q);
	for(log = 1; (1<<log) <= L[p]; log++);
	log--;

	int ans = -INF;
	for(int i = log; i >= 0; i--)
		if(L[p] - (1<<i) >= L[q])
		{
			ans = max(ans, maxcost[p][i]);
			p = anc[p][i];
		}
	if(p == q)
		return ans;
	for(int i = log; i >= 0; i--)
	{
		if(anc[p][i] != -1 && anc[p][i] != anc[q][i])
		{
			ans = max(ans, maxcost[p][i]);
			ans = max(ans, maxcost[q][i]);
			p = anc[p][i];
			q = anc[q][i];
		}
	}
	ans = max(ans, cost[p]);
	ans = max(ans, cost[q]);
	return ans;
}

void dfs(int u)
{
	for(int i = first[u]; i != -1; i = e2[i].next)
	{
		int v = e2[i].v;
		if(vis[v])
			continue;
		vis[v] = 1;
		fa[v] = u;
		cost[v] = e2[i].w;
		L[v] = L[u]+1;
		dfs(v);
	}
}

int find(int x)
{
	if(f[x] != x)
		return f[x] = find(f[x]);
	return x;
}
int main()
{
	int cas = 0;
	while(scanf("%d %d", &n, &m) != EOF)
	{
		memset(first, -1, sizeof(first));
		memset(vis, 0, sizeof(vis));
		cnt = 0;
		for(int i = 0; i < m; i++)
		{
			scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w);
		}
		sort(e, e+m, cmp);
		for(int i = 0; i <= n; i++)
			f[i] = i;
		int sum = 0;
		for(int i = 0; i < m; i++)
		{
			int u = e[i].u;
			int v = e[i].v;
			int x = find(u);
			int y = find(v);
			if(x != y)
			{
				sum++;
				f[x] = y;
				AddEdge(e[i].u, e[i].v, e[i].w);
			}
		}
		fa[1] = -1;
		cost[1] = 0;
		L[1] = 0;
		vis[1] = 1;
		dfs(1);
		pre();
		int q;
		scanf("%d", &q);
		if(cas++)
			printf("\n");
		while(q--)
		{
			int u, v;
			scanf("%d %d", &u, &v);
			printf("%d\n", query(u, v));
		}
	}
	return 0;
}

UVa 11354 Bond 最小生成树+LCA倍增,布布扣,bubuko.com

时间: 2024-12-27 21:17:01

UVa 11354 Bond 最小生成树+LCA倍增的相关文章

UVA 11354 Bond(最小生成树+lca+倍增求祖先节点)

题意:n个点m条边,每条边有一个权值,有q个询问,每次询问两点间的一条路径,使得这条路径上权值最大的边最小. 思路:很容易想到最小瓶颈路,但是查询太多,会超时,可以预处理出最小生成树,则问题转化为一棵树上的两点间路径中权值最大的那条边,设这两点为u,v,可以得到dist(u,v)=max(dist(u,lca(u,v)),dist(v,lca(v,lca))),其中lca(u,v)表示u和v的最近公共祖先,用倍增的思想预处理出每个结点的2^i的祖先fa[u][i],然后在离线求出lca后顺便计算

uva 11354 bond 最小生成树

n个城市通过m条无向边连接,回答q个询问,每个询问形式为s,t,要找到一条s到t的路使得这条路上的最大危险系数最小. 还是最小瓶颈路,可是要快速回答每次询问,先求出最小生成树,转化为有根树,即找到s到t的路径上的最大边,在这一过程中倍增查找. 预处理的复杂度为nlogn,每次查询为logn. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using na

UVA 11354 - Bond (最小生成树 + 树链剖分)

题目链接~~> 做题感悟:这题开始看到时感觉不是树不好处理,一想可以用 Kruskal 处理成树 ,然后就好解决了. 解题思路: 先用 Kruskal 处理出最小生成树,然后用树链剖分 + 线段树处理就可以了. 代码: #include<iostream> #include<sstream> #include<map> #include<cmath> #include<fstream> #include<queue> #incl

训练指南 UVA - 11354(最小生成树 + 倍增LCA)

layout: post title: 训练指南 UVA - 11354(最小生成树 + 倍增LCA) author: "luowentaoaa" catalog: true mathjax: true tags: - 最小生成树 - LCA - 图论 - 训练指南 Bond UVA - 11354 题意 给你一张无向图,然后有若干组询问,让你输出a->b的最小瓶颈路 题解 先求出最小生成树,然后对这个最小生成树做LCA. #include<bits/stdc++.h>

UVA 11354 - Bond(树链剖分)

UVA 11354 - Bond 题目链接 题意:给定一个图,要求每次询问两点,求出这两点间路径最大危险系数最小 思路:先求最小生成树,在生成树上每次询问求LCT就可以了,利用树链剖分求解 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define lson(x) ((x<<1)+1) #d

uva 11354 - Bond(树链剖分)

题目链接:uva 11354 - Bond 题目大意:给定一张图,每次询问两个节点路径上进过边的危险值的最大值的最小值. 解题思路:首先建立最小生成数,然后根据这棵树做树链剖分. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int maxn = 50005; const int INF = 0x3f

UVA - 11354 Bond(最小生成树+LCA+瓶颈路)

题意:N个点,M条路,每条路的危险度为路上各段中最大的危险度.多组询问,点s到点t的所有路径中最小的危险度. 分析: 1.首先建个最小生成树,则s到t的路径一定是危险度最小的. 原因:建最小生成树的最后一步,如果有两个相等的边可以选择,然后将两个连通块连在一起. 那不管选择哪个边,对于分别位于两个连通块的两点来说,这条边都是必经之路,而这个必经之路是这两点路径的危险度中最大的,起决定作用,所以选哪个是一样的. 2.利用lca,在找s和t最近公共祖先的过程中,不断取两者路径中的最大危险度即可. 3

UVA 11354 Bond 瓶颈路 最小生成树+LCA类似

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 下面m行是(u,v) 和边权 下面q个询问 (u, v) 在这两个点间找一条路径使得这个路径上最大的边权最小. 数据保证询问的2个点之间一定存在路径 思路: 求瓶颈路,最小生成树跑一下. 然后求lca的代码里加入边权. 因为要使得最大的边权最小,所以用最小生成树的krusal算法, 正确性证明: 我们现在有联通块G,一个孤立点u,以及G与u之间的一些边,则显然我们选择边权最小的一条边把2个联通块连接. 这个过程就是krusal. #inc

UVA 11354 Bond

Bond Time Limit: 8000ms Memory Limit: 131072KB This problem will be judged on UVA. Original ID: 1135464-bit integer IO format: %lld      Java class name: Main Once again, James Bond is on his way to saving the world. Bond's latest mission requires hi