题目链接:
题目分析:
kruscal+树剖板套板
首先在一个连通块里的两个点之间的路径上边权最小值的最大值(有点绕)一定在最大生成树上,因为最大生成树使新图连通且边权最大
然后在最大生成树上树剖/倍增求两点路径中的最小值即可,注意边权下放到点后查询时要跳过(LCA)
图可能不连通((#21)即是不连通的情况),此时需要对每棵(BST)的根(dfs)一遍
代码:
#include<bits/stdc++.h>
#define N (100000 + 10)
#define int long long
using namespace std;
inline int read() {
int cnt = 0, f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();}
return cnt * f;
}
const int INF = (1 << 30);
int n, m;
int fa[N], father[N], tot, w[N], a[N], num[N], id[N], idx, top[N], dep[N], siz[N], son[N];
int nxt[N], first[N], to[N];
int x, y, z, q;
struct node {
int u, v, dat;
}edge[N];
bool cmp (node x, node y) {
return x.dat > y.dat;
}
void add(int x, int y, int z) {nxt[++tot] = first[x], first[x] = tot, to[tot] = y, w[tot] = z;}
int get_father(int x) {return fa[x] == x ? x : fa[x] = get_father(fa[x]);}
void dfs_(int x, int Fa) {
father[x] = Fa, dep[x] = dep[Fa] + 1, siz[x] = 1;
for (register int i = first[x]; i; i = nxt[i]) {
int v = to[i];
if (v == Fa) continue;
a[v] = w[i];
dfs_(v, x);
siz[x] += siz[v];
if (siz[son[x]] < siz[v]) son[x] = v;
}
}
void dfs__(int x, int tp) {
top[x] = tp, num[x] = ++idx, id[idx] = x;
if (son[x]) dfs__(son[x], tp);
for (register int i = first[x]; i; i = nxt[i]) {
int v = to[i];
if (num[v]) continue;
dfs__(v, v);
}
}
struct node2 {
int l, r, dat;
#define l(p) tree[p].l
#define r(p) tree[p].r
#define dat(p) tree[p].dat
}tree[N << 2];
void pushup(int p) {
dat(p) = min(dat(p << 1), dat(p << 1 | 1));
}
void build (int p, int l, int r) {
l(p) = l, r(p) = r;
if (l == r) {dat(p) = a[id[l]]; return;}
int mid = (l + r) >> 1;
build (p << 1, l, mid);
build (p << 1 | 1, mid + 1, r);
pushup(p);
}
long long query (int p, int l, int r) {
if (l <= l(p) && r >= r(p)) return dat(p);
long long ans = INF;
int mid = (l(p) + r(p)) >> 1;
if (l <= mid) ans = min(ans, query(p << 1, l, r));
if (r > mid) ans = min(ans, query(p << 1 | 1, l, r));
return ans;
}
long long Query(int u, int v) {
long long ans = INF;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
ans = min(ans, query(1, num[top[u]], num[u]));
u = father[top[u]];
}
if (dep[u] < dep[v]) swap(u, v);
ans = min(ans, query(1, num[v] + 1, num[u]));
return ans;
}
signed main() {
n = read(), m = read();
for (register int i = 1; i <= n; ++i) fa[i] = i;
for (register int i = 1; i <= m; ++i) {
edge[i].u = read(), edge[i].v = read(), edge[i].dat = read();
}
sort (edge + 1, edge + m + 1, cmp);
for (register int i = 1; i <= m; i++) {
if (tot / 2 == n - 1) break;
int fx = get_father(edge[i].u), fy = get_father(edge[i].v);
if (fx == fy) continue;
fa[fy] = fx, add(edge[i].u, edge[i].v, edge[i].dat), add(edge[i].v, edge[i].u, edge[i].dat);
}
for (register int i = 1; i <= n; ++i) if (fa[i] == i) dfs_(i, 0), dfs__(i, i);
build(1, 1, n);
q = read();
for (register int i = 1; i <= q; ++i) {
x = read(), y = read();
if (get_father(x) != get_father(y)) {printf("-1
"); continue;}
printf("%lld
", Query(x, y));
}
return 0;
}