题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=54643#problem/G
题意:n个点m条无向边相连,每条道路都有一个危险系数,对于q个询问,每个询问都包含一个起点s和终点t的路,使得途径所有边最大危险系数最小
思路:题目要求瓶颈路,但由于需要快速回答询问,所以需要做成易于查询的结构。先求MST,然后改为有根树,并利用类似LCA的办法,通过预处理计算anc和maxcost数组,其中anc[i][j]表示结点i的第2^j级祖先的编号,max[i][j]表示结点i和它的2^j级祖先之间的路径上的最大权值. 预处理后,我们对于每次查询的两个结点p, q,可以先把p和q提升到同一级的位置,让后利用类似二进制展开的方法不断把p和q同时往上“提”,并且更新最大边权
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <utility>
using namespace std;
const int maxn = 100010;
const int maxm = 200020;
const int inf = 0x3f3f3f3f;
int n, m;
int fa[maxn], cost[maxn], h[maxn];
int anc[maxn][20];
int mcost[maxn][20];
struct edge
{
int from, to, w, nxt;
edge() {}
edge(int from, int to, int w) : from(from), to(to), w(w) {}
bool operator < (const edge & rhs) const
{
return w > rhs.w;
}
};
struct Prim
{
int head[maxn], dis[maxn], vis[maxn];
int dep[maxn], pre[maxn], cnt;
int n, sum;
edge e[maxm];
void init(int n)
{
this -> n = n;
cnt = 0;
sum = 0;
memset(head, -1, sizeof(head));
}
void add(int u, int v, int w)
{
e[cnt].from = u;
e[cnt].to = v;
e[cnt].w = w;
e[cnt].nxt = head[u];
head[u] = cnt++;
}
void prim(int s)
{
priority_queue <edge> que;
memset(dis, inf, sizeof(dis));
memset(vis, 0, sizeof(vis));
memset(dep, 0, sizeof(dep));
memset(pre, -1, sizeof(pre));
vis[s] = 1;
dis[s] = 0;
for(int i = head[s]; ~i; i = e[i].nxt)
{
int v = e[i].to;
dis[v] = e[i].w;
que.push(edge(s, v, e[i].w));
}
while(!que.empty())
{
edge now = que.top();
que.pop();
int u = now.to;
if(vis[u])
continue;
vis[u] = 1;
pre[u] = now.from;
dep[u] = dep[now.from] + 1;
dis[u] = now.w;
sum += now.w;
for(int i = head[u]; ~i; i = e[i].nxt)
{
int v = e[i].to;
int w = e[i].w;
if(!vis[v] && dis[v] > w)
{
dis[v] = e[i].w;
que.push(edge(u, v, w));
}
}
}
}
} mst;
void preprocess()
{
for (int i = 1; i <= n; i++)
{
anc[i][0] = fa[i];
mcost[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];
mcost[i][j] = max(mcost[i][j - 1], mcost[a][j - 1]);
}
}
}
}
int query(int p, int q)
{
int log;
if (h[p] < h[q]) swap(p, q);
for (log = 1; (1 << log) <= h[p]; log++);
log--;
int ans = -inf;
for (int i = log; i >= 0; i--)
{
if (h[p] - (1 << i) >= h[q])
{
ans = max(ans, mcost[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, mcost[p][i]);
p = anc[p][i];
ans = max(ans, mcost[q][i]);
q = anc[q][i];
}
}
ans = max(ans, max(cost[p], cost[q]));
return ans;
}
int main()
{
int ca = 0;
while(~scanf("%d%d", &n, &m))
{
if(ca++)
putchar('\n');
mst.init(n);
for(int i = 0; i < m; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
mst.add(u, v, w);
mst.add(v, u, w);
}
mst.prim(1);
// cout << mst.sum << endl;
for(int i = 1; i <= n; i++)
{
fa[i] = mst.pre[i];
cost[i] = mst.dis[i];
h[i] = mst.dep[i];
// printf("%d %d %d\n", fa[i], cost[i], h[i]);
}
preprocess();
int q;
scanf("%d", &q);
while(q--)
{
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", query(x, y));
}
}
return 0;
}