题目链接: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 是 pfor(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\n",solver.query(u,v));}}return 0; }