UVa 11354 Bond 最小生成树+LCA倍增
2017-09-12 00:12
519 查看
题目大意: n 个点 m 条边的图 q 次询问,每条边都有一个危险系数,每次询问要求一条从 s 到 t 的路径使所有边的最大危险系数最小
思路:
先求出最小生成树,这样能保证图中所有路径的值最小。
接着dfs建有根树,记录 fa[i] 和 val[i] 分别表示节点 i 的父亲节点编号和 i 与父亲的边的权值,同时处理出深度deep[i]
利用倍增思想预处理出LCA和两点之间路径的最大权值记为 STfa[i][j] , STcost[i][j]
接着就是每次 logn 的询问了
细节看代码:
/*************************************************************************
> Author: wzw-cnyali
> Created Time: 2017/9/11 12:41:53
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#prag\
ma GCC optimize("O3")
using namespace std;
#define REP(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)
#define DREP(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)
#define EREP(i, a) for(register int i = (be[a]); i != -1; i = nxt[i])
#define mem(a, b) memset((a), b, sizeof(a))
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template <class T>
T read(T sum = 0, T fg = 0)
{
char c = getchar();
while(c < '0' || c > '9') { fg |= c == '-'; c = getchar(); }
while(c >= '0' && c <= '9') { sum = sum * 10 + c - '0'; c = getchar(); }
return fg ? -sum : sum;
}
const int Size = 100010;
struct Edge
{
int x, y, w;
void input()
{
x = read<int>();
y = read<int>();
w = read<int>();
}
friend bool operator < (Edge a, Edge b)
{
return a.w < b.w;
}
}edge[Size];
int to[Size], nxt[Size], be[Size], w[Size], e;
void add(int x, int y, int z) { to[e] = y; nxt[e] = be[x]; be[x] = e; w[e] = z; e++; }
void add_edge(int x, int y, int z) { add(x, y, z); add(y, x, z); }
void init() { mem(be, -1); e = 0; }
int n, m;
int fa[Size];
int father(int x)
{
return fa[x] = x == fa[x] ? x : father(fa[x]);
}
bool merge(int x, int y)
{
int fx = father(x), fy = father(y);
if(fx != fy) { fa[fx] = fy; return 1; }
else return 0;
}
void Kruskal()
{
init();
REP(i, 1, n) fa[i] = i;
sort(edge + 1, edge + m + 1);
int count = 0;
REP(i, 1, m)
{
int x = edge[i].x, y = edge[i].y, w = edge[i].w;
if(merge(x, y))
{
add_edge(x, y, w);
if(++count == n - 1) break;
}
}
}
int deep[Size], Fa[Size], val[Size];
void dfs_init(int x, int f, int depth)
{
Fa[x] = f; deep[x] = depth;
EREP(i, x)
{
int y = to[i];
if(y != f)
{
val[y] = w[i];
dfs_init(y, x, depth + 1);
}
}
}
int STfa[Size][20];
int STcost[Size][20];
void ST_init()
{
mem(STfa, -1);
REP(i, 1, n)
{
STcost[i][0] = val[i];
STfa[i][0] = Fa[i];
}
for(int j = 1; (1 << j) <= n; ++j)
{
REP(i, 1, n)
{
int a = STfa[i][j - 1];
if(a != -1)
{
STfa[i][j] = STfa[a][j - 1];
STcost[i][j] = max(STcost[i][j - 1], STcost[a][j - 1]);
}
}
}
}
int query(int L, int R)
{
if(deep[L] < deep[R]) swap(L, R);
int lg = log2(deep[L]);
int ans = -1;
DREP(i, lg, 0)
{
if(deep[L] - (1 << i) >= deep[R])
{
chkmax(ans, STcost[L][i]);
L = STfa[L][i];
}
}
if(L == R) return ans;
DREP(i, lg, 0)
{
if(STfa[L][i] != -1 && STfa[L][i] != STfa[R][i])
{
chkmax(ans, STcost[L][i]);
chkmax(ans, STcost[R][i]);
L = STfa[L][i]; R = STfa[R][i];
}
}
chkmax(ans, val[L]); chkmax(ans, val[R]);
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
int Case;
while(scanf("%d%d", &n, &m) != EOF)
{
if(Case++) puts("");
REP(i, 1, m) edge[i].input();
Kruskal();
dfs_init(1, -1, 0);
ST_init();
int q = read<int>();
while(q--)
{
int x = read<int>(), y = read<int>();
int ans = query(x, y);
printf("%d\n", ans);
}
}
return 0;
}
思路:
先求出最小生成树,这样能保证图中所有路径的值最小。
接着dfs建有根树,记录 fa[i] 和 val[i] 分别表示节点 i 的父亲节点编号和 i 与父亲的边的权值,同时处理出深度deep[i]
利用倍增思想预处理出LCA和两点之间路径的最大权值记为 STfa[i][j] , STcost[i][j]
接着就是每次 logn 的询问了
细节看代码:
/*************************************************************************
> Author: wzw-cnyali
> Created Time: 2017/9/11 12:41:53
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#prag\
ma GCC optimize("O3")
using namespace std;
#define REP(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)
#define DREP(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)
#define EREP(i, a) for(register int i = (be[a]); i != -1; i = nxt[i])
#define mem(a, b) memset((a), b, sizeof(a))
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template <class T>
T read(T sum = 0, T fg = 0)
{
char c = getchar();
while(c < '0' || c > '9') { fg |= c == '-'; c = getchar(); }
while(c >= '0' && c <= '9') { sum = sum * 10 + c - '0'; c = getchar(); }
return fg ? -sum : sum;
}
const int Size = 100010;
struct Edge
{
int x, y, w;
void input()
{
x = read<int>();
y = read<int>();
w = read<int>();
}
friend bool operator < (Edge a, Edge b)
{
return a.w < b.w;
}
}edge[Size];
int to[Size], nxt[Size], be[Size], w[Size], e;
void add(int x, int y, int z) { to[e] = y; nxt[e] = be[x]; be[x] = e; w[e] = z; e++; }
void add_edge(int x, int y, int z) { add(x, y, z); add(y, x, z); }
void init() { mem(be, -1); e = 0; }
int n, m;
int fa[Size];
int father(int x)
{
return fa[x] = x == fa[x] ? x : father(fa[x]);
}
bool merge(int x, int y)
{
int fx = father(x), fy = father(y);
if(fx != fy) { fa[fx] = fy; return 1; }
else return 0;
}
void Kruskal()
{
init();
REP(i, 1, n) fa[i] = i;
sort(edge + 1, edge + m + 1);
int count = 0;
REP(i, 1, m)
{
int x = edge[i].x, y = edge[i].y, w = edge[i].w;
if(merge(x, y))
{
add_edge(x, y, w);
if(++count == n - 1) break;
}
}
}
int deep[Size], Fa[Size], val[Size];
void dfs_init(int x, int f, int depth)
{
Fa[x] = f; deep[x] = depth;
EREP(i, x)
{
int y = to[i];
if(y != f)
{
val[y] = w[i];
dfs_init(y, x, depth + 1);
}
}
}
int STfa[Size][20];
int STcost[Size][20];
void ST_init()
{
mem(STfa, -1);
REP(i, 1, n)
{
STcost[i][0] = val[i];
STfa[i][0] = Fa[i];
}
for(int j = 1; (1 << j) <= n; ++j)
{
REP(i, 1, n)
{
int a = STfa[i][j - 1];
if(a != -1)
{
STfa[i][j] = STfa[a][j - 1];
STcost[i][j] = max(STcost[i][j - 1], STcost[a][j - 1]);
}
}
}
}
int query(int L, int R)
{
if(deep[L] < deep[R]) swap(L, R);
int lg = log2(deep[L]);
int ans = -1;
DREP(i, lg, 0)
{
if(deep[L] - (1 << i) >= deep[R])
{
chkmax(ans, STcost[L][i]);
L = STfa[L][i];
}
}
if(L == R) return ans;
DREP(i, lg, 0)
{
if(STfa[L][i] != -1 && STfa[L][i] != STfa[R][i])
{
chkmax(ans, STcost[L][i]);
chkmax(ans, STcost[R][i]);
L = STfa[L][i]; R = STfa[R][i];
}
}
chkmax(ans, val[L]); chkmax(ans, val[R]);
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
int Case;
while(scanf("%d%d", &n, &m) != EOF)
{
if(Case++) puts("");
REP(i, 1, m) edge[i].input();
Kruskal();
dfs_init(1, -1, 0);
ST_init();
int q = read<int>();
while(q--)
{
int x = read<int>(), y = read<int>();
int ans = query(x, y);
printf("%d\n", ans);
}
}
return 0;
}
相关文章推荐
- UVa 11354 - Bond(最小生成树+倍增lca)
- 【UVa】11354 Bond 最小生成树,动态LCA,倍增思想
- UVA 11354 Bond(最小生成树+lca+倍增求祖先节点)
- UVA 11354 Bond(最小生成树+LCA倍增)
- UVA - 11354Bond最小生成树,LCA寻找近期公共祖先
- UVA 11354 Bond(最小生成树+LCA)
- UVA - 11354Bond最小生成树,LCA寻找最近公共祖先
- Uva 11354 Bond(最小生成树+LCA)
- 【UVA 11354】 Bond (最小瓶颈生成树、树上倍增)
- UVA 11354 Bond 瓶颈路 最小生成树+LCA类似
- UVA11354[Bond] 倍增求LCA+Kruskal求最小瓶颈生成树
- UVA 11354 Bond(最小瓶颈路+倍增)
- Kruskal,最小生成树,树链剖分,LCA(邦德,UVA 11354)
- uva 11354最小生成树瓶颈路(lca算法实现)(rmq在多校二中有一道题)
- UVA 11354 LCA+最小生成树
- uva 11354 bond 最小生成树
- UVA 11354 Bond (最小生成树 + 树链剖分)
- UVA-11354-Bond(树上倍增,dp,MST,LCA)
- UVA - 11354 Bond(生成树+LCA)
- BZOJ 3732 Network —— 最小生成树 + 倍增LCA