题目链接:点击打开链接
题意:给出一张n个点m条边的无向图, 每条边有一个危险度,有q个询问, 每次给出两个点s、t,找一条路, 使得路径上的最大危险度最小。
思路:首先,我们可以发现,如果求一个最小生成树, 那么任意两点, 在生成树上有唯一路径, 而且这条路径上的最大危险值一定最小。 但是n和q都太大, 如果直接顺着树走,每次询问最大复杂度O(n), 那么复杂度高达O(n^2),会超时。 我们知道, 并查集在用了路径压缩之后效率高达O(n), 但是却破坏了树形结构, 所以不能用路径压缩。 然而我们经常忽视了按秩合并这个方法, 即使不用路径压缩, 仅仅靠按秩合并, 复杂度也可低至O(logn)。 因此我们只需按秩合并, 然后询问的时候向根回溯就行了, 复杂度mlogn。
细节参见代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int mod = 1000000000 + 7;
const int INF = 1000000000 + 7;
const int maxn = 50000 + 10;
int T,n,m,p[maxn],ra[maxn],edge[maxn],vis[maxn];
struct node {
int a, b, c;
bool operator < (const node& rhs) const {
return c < rhs.c;
}
}a[100000 + 10];
int _find(int x) { return p[x] == x ? x : _find(p[x]); }
void Union(int a, int b, int c) {
int x = _find(a);
int y = _find(b);
if(x == y) return ;
if(ra[x] < ra[y]) {
p[x] = y;
edge[x] = c;
}
else {
p[y] = x;
edge[y] = c;
if(ra[x] == ra[y]) ra[x]++;
}
}
void pre() {
sort(a, a+m);
for(int i=1;i<=n;i++) {
p[i] = i;
ra[i] = 0;
vis[i] = -1;
}
for(int i=0;i<m;i++) {
Union(a[i].a,a[i].b,a[i].c);
}
}
int query(int x, int y) {
int ans1 = 0, ans2 = -1;
int cur = x;
while(true) {
vis[cur] = ans1;
if(cur == p[cur]) break;
ans1 = max(ans1, edge[cur]);
cur = p[cur];
}
cur = y;
while(true) {
if(vis[cur] >= 0) {
ans2 = max(ans2, vis[cur]); break;
}
if(cur == p[cur]) break;
ans2 = max(ans2, edge[cur]);
cur = p[cur];
}
cur = x;
while(true) {
vis[cur] = -1;
if(cur == p[cur]) break;
cur = p[cur];
}
return ans2;
}
int u,v,q,kase=0;
int main() {
while(~scanf("%d%d",&n,&m)) {
for(int i=0;i<m;i++) {
scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c);
}
if(kase) printf("\n");
else ++kase;
pre();
scanf("%d",&q);
while(q--) {
scanf("%d%d",&u,&v);
printf("%d\n",query(u, v));
}
}
return 0;
}