题目链接:https://vjudge.net/contest/144221#problem/B
题意:找一条从 s 到 t 的路,使得瓶颈路最小。
点的数目是10^4,如果向之前的方案求 maxcost数组,O(n*n)时间是过不了的,这个时候,用到了增倍祖先。
关于倍增祖先:http://m.w2bc.com/article/177601
我要补充的是,倍增祖先的优点,是在于倍增,他写的案例,没有体现出倍增,这里强调一下。有点像二分的思想;
利用倍增祖先初始化maxcost[i][j]数组,maxcost[i][j] 在倍增祖先里面表示的,结点 i 的第2j级祖先之间的瓶颈。
用O(nlogn)初始化,然后,查询是O(logn)。
#include <bits/stdc++.h> using namespace std; const int maxn = 50000 + 10; const int INF = 0x3f3f3f3f; const int logmaxn = 20; int n,m; struct Edge { int u,v,d; bool operator < (const Edge& rhs) const { return d < rhs.d; } }; Edge e[maxn]; int pa[maxn]; int Find_Set(int x) { if(x!=pa[x]) pa[x] = Find_Set(pa[x]); return pa[x]; } vector<int> G[maxn],C[maxn]; struct LCA { int n; int fa[maxn]; int cost[maxn]; int L[maxn]; int anc[maxn][logmaxn]; int maxcost[maxn][logmaxn]; void preprocess() { for(int i=0; i<n; i++) { anc[i][0] = fa[i]; maxcost[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=0; i<n; i++) { if(anc[i][j-1]!=-1) { int a = anc[i][j-1]; anc[i][j] = anc[a][j-1]; maxcost[i][j] = max(maxcost[i][j-1],maxcost[a][j-1]); } } } } int query (int p,int q) { int log; if(L[p]<L[q]) swap(p,q); for(log=1; (1<<log)<=L[p]; log++); log--; int ans = -INF; for(int i=log; i>=0; i--) { if(L[p]-(1<<i)>=L[q]) { ans = max(ans,maxcost[p][i]); p = anc[p][i]; } } if(p==q) return ans; //lca 是 p for(int i=log; i>=0; i--) { if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]) { ans = max(ans,maxcost[p][i]); p = anc[p][i]; ans = max(ans,maxcost[q][i]); q = anc[q][i]; } } ans = max(ans,cost[p]); ans = max(ans,cost[q]); return ans; //LCA 是 fa[p] = fa[q]; } }; LCA solver; void dfs(int u,int fa,int level) { solver.L[u] = level; for(int i=0; i<G[u].size(); i++) { int v = G[u][i]; if(G[u][i]!=fa) { solver.fa[v] = u; solver.cost[v] = C[u][i]; dfs(G[u][i],u,level+1); } } } int main() { //freopen("in.txt","r",stdin); int kase = 1; while(scanf("%d%d",&n,&m)==2&&n) { for(int i=0; i<m; i++) { int u,v,d; scanf("%d%d%d",&u,&v,&d); u--; v--; e[i] = (Edge) { u,v,d }; } sort(e,e+m); for(int i=0; i<n; i++) { pa[i] = i; G[i].clear(); C[i].clear(); } for(int i=0; i<m; i++) { int u = e[i].u; int v = e[i].v; int fx = Find_Set(u); int fy = Find_Set(v); if(fx!=fy) { pa[fx] = fy; G[u].push_back(v); C[u].push_back(e[i].d); G[v].push_back(u); C[v].push_back(e[i].d); } } solver.n = n; dfs(0,-1,0); solver.preprocess(); if(kase++!=1) puts(""); int Q; scanf("%d",&Q); while(Q--) { int u,v; scanf("%d%d",&u,&v); u--; v--; printf("%d ",solver.query(u,v)); } } return 0; }