【Luogu P1967】貨車運輸
阿新 • • 發佈:2021-10-14
https://www.luogu.com.cn/problem/P1967
分析
題意為求任意兩城市之間能夠聯通的線路中所有單個線路中最小值的最大值。
首先做最大生成樹生成陣列\(tree\),然後\(dfs\)每棵樹獲得陣列\(deep\)(\(deep[i]\)表示\(i\)節點在所屬的樹中的深度,根節點深度為\(0\)),\(mindist[i][0]\)(\(mindist[i][j]\)表示從節點\(i\)向上走\(2^j\)步過程中所經歷的路徑的最小值),\(p[x][0]\)(\(p[x][y]\)表示從節點\(x\)向上走\(2^y\)步所到達的節點)。
查詢時首先用並查集判斷是否能聯通,然後用\(lca\)
#include <bits/stdc++.h> #define P pair<int, int> #define PI pair<int,P> #define INF 0x3fffffff using namespace std; int n,m,x,y,d,q,deep[10010],p[10010][15],fa[10010],mdep=0,mindist[10010][15]; vector<PI> V; //dis node1 node2 vector<P> tree[10010]; //dis node vector<int> root; int find(int n) { return fa[n]==n?n:fa[n]=find(fa[n]); } void build() { //cout<<V.size()<<endl; for(auto tmp=V.rbegin();tmp<V.rend();tmp++) { int di=tmp->first,a=tmp->second.first, b=tmp->second.second; if(find(a)!=find(b)) { //cout<<a<<" "<<b<<" "<<di<<endl; tree[a].push_back(P(di,b)); tree[b].push_back(P(di,a)); fa[find(a)]=find(b); } } } void dfs(int r,int fa) { p[r][0]=fa; deep[r]=deep[fa]+1; if(deep[r]>mdep)mdep=deep[r]; for(auto x:tree[r]) { if(x.second!=fa) { mindist[x.second][0]=x.first; dfs(x.second,r); } } } int query(int a,int b) { int ans=INF; if(deep[a]<deep[b])swap(a,b); //a>=b int i=0; for(;(1<<i)<=deep[a];i++); i--; for(int k=i;k>=0;k--) { if(deep[a]-(1<<k)>=deep[b]) { ans=min(ans,mindist[a][k]); a=p[a][k]; } } if(a==b)return ans; for(int k=i;k>=0;k--) { if(deep[a]>=(1<<k)&&p[a][k]!=p[b][k]) { ans=min(min(ans,mindist[a][k]),mindist[b][k]); a=p[a][k]; b=p[b][k]; } } ans=min(ans,min(mindist[a][0],mindist[b][0])); return ans; } int main() { scanf("%d%d",&n,&m); //get edges for(int i=0;i<m;i++) { scanf("%d%d%d",&x,&y,&d); V.push_back(PI(d,P(x,y))); } sort(V.begin(),V.end()); for(int i=1;i<=n;i++)fa[i]=i; //build tree build(); deep[0]=-1; for(int i=1;i<=n;i++) if(fa[i]==i)dfs(i,0); //set i node as root => deep and p[x][0](father) int j=1,k=2;//k=2^j while(k<=mdep) { for(int i=1;i<=n;i++) { if(deep[i]>=k) { p[i][j]=p[p[i][j-1]][j-1]; mindist[i][j]=min(mindist[i][j-1],mindist[p[i][j-1]][j-1]); } } j++; k*=2; } scanf("%d",&q); while(q--) { scanf("%d%d",&x,&y); if(find(x)!=find(y))printf("-1\n"); else printf("%d\n",query(x,y)); } return 0; }