您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: