[题目链接]
https://www.luogu.org/problemnew/show/P1967
[算法]
可以证明答案一定为最大生成树上两点路径中的最小值
树上倍增即可
时间复杂度 : O((N + Q) log N)
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXN 10010 #define MAXM 50010 #define MAXLOG 20 const int inf = 2e9; struct info { int u,v,w; } a[MAXM]; struct edge { int to,w,nxt; } e[MAXM << 1]; int i,n,m,u,v,w,x,y,tot,cnt,q; int fa[MAXN],color[MAXN],head[MAXN],depth[MAXN]; int anc[MAXN][MAXLOG],mn[MAXN][MAXLOG]; bool visited[MAXN]; namespace IO { template <typename T> inline void read(T &x) { int f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; } for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } template <typename T> inline void write(T x) { if (x < 0) { putchar('-'); x = -x; } if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> inline void writeln(T x) { write(x); puts(""); } } ; inline bool cmp(info a,info b) { return a.w > b.w; } inline void addedge(int u,int v,int w) { tot++; e[tot] = (edge){v,w,head[u]}; head[u] = tot; } inline int get_root(int x) { if (fa[x] == x) return x; return fa[x] = get_root(fa[x]); } inline void kruskal() { int i,su,sv,u,v,w; sort(a + 1,a + m + 1,cmp); for (i = 1; i <= m; i++) { u = a[i].u; v = a[i].v; w = a[i].w; su = get_root(u); sv = get_root(v); if (su != sv) { fa[sv] = su; addedge(u,v,w); addedge(v,u,w); } } } inline void dfs(int u,int id) { int i,v,w; color[u] = id; visited[u] = true; for (i = 1; i < MAXLOG; i++) { anc[u][i] = anc[anc[u][i - 1]][i - 1]; mn[u][i] = min(mn[u][i - 1],mn[anc[u][i - 1]][i - 1]); } for (i = head[u]; i; i = e[i].nxt) { v = e[i].to; w = e[i].w; if (!visited[v]) { depth[v] = depth[u] + 1; anc[v][0] = u; mn[v][0] = w; dfs(v,id); } } } inline int query(int x,int y) { int i,t; int ret = inf; if (color[x] != color[y]) return -1; if (depth[x] > depth[y]) swap(x,y); t = depth[y] - depth[x]; for (i = 0; i < MAXLOG; i++) { if (t & (1 << i)) { ret = min(ret,mn[y][i]); y = anc[y][i]; } } if (x == y) return ret; for (i = MAXLOG - 1; i >= 0; i--) { if (anc[x][i] != anc[y][i]) { ret = min(ret,min(mn[x][i],mn[y][i])); x = anc[x][i]; y = anc[y][i]; } } if (depth[x] == 0) return ret; ret = min(ret,min(mn[x][0],mn[y][0])); return ret; } int main() { IO :: read(n); IO :: read(m); for (i = 1; i <= m; i++) { IO :: read(a[i].u); IO :: read(a[i].v); IO :: read(a[i].w); } for (i = 1; i <= n; i++) fa[i] = i; kruskal(); for (i = 1; i <= n; i++) { if (!visited[i]) dfs(i,++cnt); } IO :: read(q); while (q--) { IO :: read(x); IO :: read(y); IO :: writeln(query(x,y)); } return 0; }