嗯……我知道正解是LCA倍增……但是补这个题的时候第一反应就是树剖,于是我就愉快地写树剖了……
用树剖的话复杂度会多一个log不过常数写的小点话几乎可以忽略不计。代码量比正解大那么1000b的样子……毕竟有个线段树还有两个dfs
先用kruskal建个最大生成森林出来,然后把每棵树剖分一下就行了。线段树可以用一个,因为互相不影响
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
int N, M, Q;
struct e {
int u, v, w;
bool operator < (const e &b) const {
return w > b.w;
}
}edge[50005];
queue <e> q;
int f[10005];
int find(int x) { return (x == f[x]) ? x : f[x] = find(f[x]); }
struct ed {
int v, w, next;
}e[100005];
int head[10005], k = 1;
inline void adde(int u, int v, int w)
{
e[k] = (ed) { v, w, head[u] }; head[u] = k ++;
e[k] = (ed) { u, w, head[v] }; head[v] = k ++;
}
int vis[10005], belong[10005], rcnt, root[10005];
int fa[10005], son[10005], size[10005], dep[10005];
int top[10005], w[10005], tot;
void dfs(int u)
{
size[u] = 1; son[u] = 0;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].v; if (v == fa[u]) continue;
fa[v] = u; dep[v] = dep[u] + 1;
vis[v] = 1; belong[v] = rcnt;
dfs(v); size[u] += size[v];
if (size[v] > size[son[u]]) son[u] = v;
}
}
void build_tree(int u, int tp)
{
w[u] = ++ tot; top[u] = tp;
if (son[u]) build_tree(son[u], tp);
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].v; if (v == fa[u] || v == son[u]) continue;
build_tree(v, v);
}
}
#define lc (u << 1)
#define rc (u << 1 | 1)
namespace BIT {
int mmin[10005 << 2];
inline void init() { memset(mmin, 0x3f, sizeof(mmin)); }
void update(int u, int l, int r, const int &pos, const int &c)
{
if (l == r) { mmin[u] = c; return; }
int mid = (l + r) >> 1;
if (pos <= mid) update(lc, l, mid, pos, c);
else update(rc, mid + 1, r, pos, c);
mmin[u] = min(mmin[lc], mmin[rc]);
}
int Min(int u, int l, int r, int L, int R)
{
if (l == L && r == R) return mmin[u];
int mid = (l + r) >> 1;
if (R <= mid) return Min(lc, l, mid, L, R);
if (L > mid) return Min(rc, mid + 1, r, L, R);
return min(Min(lc, l, mid, L, mid), Min(rc, mid + 1, r, mid + 1, R));
}
}
int Query(int u, int v)
{
int f1 = top[u], f2 = top[v], res = 0x3f3f3f3f;
while (f1 ^ f2) {
if (dep[f1] > dep[f2]) { swap(f1, f2); swap(u, v); }
res = min(res, BIT :: Min(1, 1, tot, w[f2], w[v]));
v = fa[f2]; f2 = top[v];
}
if (u == v) return res;
if (dep[u] > dep[v]) swap(u, v);
return min(res, BIT :: Min(1, 1, tot, w[son[u]], w[v]));
}
int main()
{
cin >> N >> M;
for (int i = 1; i <= M; ++ i) scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
sort(edge + 1, edge + M + 1);
for (int i = 1; i <= N; ++ i) f[i] = i;
for (int i = 1; i <= M; ++ i) {
int u = edge[i].u, v = edge[i].v;
if (find(u) == find(v)) continue;
f[f[u]] = f[v]; adde(u, v, edge[i].w);
q.push(edge[i]);
}
for (int i = 1; i <= N; ++ i) if (!vis[i]) {
vis[i] = 1; belong[i] = ++rcnt; root[rcnt] = i; dfs(i);
}
for (int i = 1; i <= rcnt; ++ i) build_tree(root[i], root[i]);
BIT :: init();
while (q.size()) {
struct e temp = q.front(); q.pop();
int u = temp.u, v = temp.v; if (dep[v] > dep[u]) swap(u, v);
BIT :: update(1, 1, tot, w[u], temp.w);
}
for (cin >> Q; Q --; ) {
int x, y; scanf("%d%d", &x, &y);
if (belong[x] ^ belong[y]) puts("-1");
else printf("%d\n", Query(x, y));
}
return 0;
}