您的位置:首页 > 其它

BZOJ 3732 Network —— 最小生成树 + 倍增LCA

2017-07-21 11:02 429 查看
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3732

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 < = 20,000)。 

每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Input

第一行: 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点的所有路径中,最长的边最小值是多少?

Output

 对每个询问,输出最长的边最小值是多少。

Sample Input

6 6 8

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

Sample Output

5

5

5

4

4

7

4

5

HINT

1 <= N <= 15,000 

1 <= M <= 30,000 

1 <= d_j <= 1,000,000,000 

1 <= K <= 15,000

题解:

由题目可知,此图为连通图

所有路径最长边的最小值,即为最小生成树下路径的最长边。因为在最小生成树下,所有边都是最优的,所以保证了最小值。那自然在最小生成树的路径下,最长边即为所求的边。

步骤:

1.构造最小生成树(无根树)。

2.将最小生成树构造为有根数,并用倍增LCA求出每个节点到第2^i个祖先的路径上的最长边。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
#define ms(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int mod = 1e9+7;
const int maxn = 3e4+10;
const int DEG = 20;

struct node
{
int u, v, w;
bool operator<(const node &x)const {
return w<x.w;
}
}e[maxn];

struct edge
{
int to, w, next;
}edge[maxn*2];

int n, m,k;
int head[maxn], tot;
int fa[maxn][DEG], deg[maxn], ma[maxn][DEG], be[maxn];

int find(int x) { return be[x]==x?x:x=find(be[x]); }

void add(int u, int v, int w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}

void bfs(int root)
{
queue<int>que;
deg[root] = 0;
ma[root][0] = 0;
fa[root][0] = root;
que.push(root);
while(!que.empty())
{
int tmp = que.front();
que.pop();
for(int i = 1; i<DEG; i++)
fa[tmp][i] = fa[fa[tmp][i-1]][i-1], ma[tmp][i] = max( ma[tmp][i-1], ma[fa[tmp][i-1]][i-1]);
for(int i = head[tmp]; i!=-1; i = edge[i].next)
{
int v = edge[i].to, w = edge[i].w;
if(v==fa[tmp][0]) continue;
deg[v] = deg[tmp]+1;
fa[v][0] = tmp;
ma[v][0] = w;
que.push(v);
}
}
}

int LCA(int u, int v)
{
int ans = 0;
if(deg[u]>deg[v]) swap(u,v);
int hu = deg[u], hv = deg[v];
int tu = u, tv = v;
for(int det = hv-hu, i = 0; det; det>>=1, i++)
if(det&1)
ans = max(ans, ma[tv][i]), tv = fa[tv][i];

if(tv==tu) return ans;
for(int i = DEG-1; i>=0; i--)
{
if(fa[tu][i]==fa[tv][i]) continue;
ans = max(ans, max( ma[tu][i], ma[tv][i] ) );
tu = fa[tu][i];
tv = fa[tv][i];
}
return ans = max(ans, max( ma[tu][0], ma[tv][0]) );
}

int main()
{
tot = 0;
ms(head, -1);
ms(ma,0);
scanf("%d%d%d",&n,&m,&k);
for(int i = 0; i<m; i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);

sort(e,e+m);
for(int i = 1; i<=n; i++)
be[i] = i;
for(int i = 0; i<m; i++)
{
int u = find(e[i].u), v = find(e[i].v);
if(u!=v)
{
be[u] = v;
add(e[i].u, e[i].v, e[i].w);
add(e[i].v, e[i].u, e[i].w);
}
}

bfs(1);
for(int i = 0; i<k; i++)
{
int u, v;
scanf("%d%d",&u,&v);
printf("%d\n",LCA(u,v));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: