1. 程式人生 > 其它 >NOIP 2013 提高組 洛谷P1967 貨車運輸 (Kruskal重構樹)

NOIP 2013 提高組 洛谷P1967 貨車運輸 (Kruskal重構樹)

題目:

A 國有 nn 座城市,編號從 11 到 nn,城市之間有 mm 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。

現在有 qq 輛貨車在運輸貨物, 司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。

 

 

對於每一組詢問,相當於求點x到點y中所有路徑中最小邊權的最大值,這樣就是貨車的最大載重。

那麼這顯然可以用Kruskal重構樹來解決,將重構樹建成大根堆,就可以求最大邊權的最小值;同理,小根堆就是最小邊權的最大值。

那麼做這道題就是重構樹的模板題了。複雜度O(q logn)。

 1 #include<bits/stdc++.h>
 2 using namespace
std; 3 const int N=2e5+10; 4 struct edge{ 5 int u,v,w; 6 bool operator < (const edge &x){ 7 return w>x.w; //小根堆 8 } 9 }e[N]; 10 vector<int> g[N]; 11 int n,m,q,cnt,fa[N],vis[N],val[N],d[N],f[N][30]; 12 int find(int x){ 13 return fa[x]==x?fa[x]:fa[x]=find(fa[x]);
14 } 15 16 void kruskal(){ 17 sort(e+1,e+m+1); 18 for(int i=1;i<=n;i++) fa[i]=i; 19 for(int i=1;i<=m;i++){ 20 int fu=find(e[i].u),fv=find(e[i].v); 21 if(fu!=fv){ 22 val[++cnt]=e[i].w; 23 fa[cnt]=fa[fu]=fa[fv]=cnt; 24 g[cnt].push_back(fu);
25 g[cnt].push_back(fv); 26 g[fu].push_back(cnt); 27 g[fv].push_back(cnt); 28 } 29 } 30 } 31 32 void dfs(int u,int fa){ 33 d[u]=d[fa]+1,f[u][0]=fa,vis[u]=1; 34 for(int i=1;(1<<i)<=d[u];i++) 35 f[u][i]=f[f[u][i-1]][i-1]; 36 for(int i=0;i<g[u].size();i++){ 37 int v=g[u][i]; 38 if(v!=fa) dfs(v,u); 39 } 40 } 41 42 int lca(int x,int y){ 43 if(d[x]<d[y]) swap(x,y); 44 for(int i=25;i>=0;i--) 45 if(d[f[x][i]]>=d[y]) x=f[x][i]; 46 if(x==y) return x; 47 for(int i=25;i>=0;i--) 48 if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 49 return f[x][0]; 50 } 51 52 int main(){ 53 scanf("%d%d",&n,&m); 54 cnt=n; 55 for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 56 kruskal(); 57 for(int i=1;i<=cnt;i++){//注意圖可能是個森林,不要漏掉 58 if(!vis[i]){ 59 int f=find(i); 60 dfs(f,0); 61 } 62 } 63 scanf("%d",&q); 64 while(q--){ 65 int u,v; 66 scanf("%d%d",&u,&v); 67 if(find(u)!=find(v)) cout<<-1<<endl; 68 else cout<<val[lca(u,v)]<<endl; 69 } 70 return 0; 71 }