洛谷1967貨物運輸(kruskal+lca倍增)
阿新 • • 發佈:2019-01-28
題目描述
A 國有 n 座城市,編號從 1 到 n,城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 q 輛貨車在運輸貨物, 司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。輸入輸出格式
輸入格式:
輸入檔名為 truck.in。
輸入檔案第一行有兩個用一個空格隔開的整數 n,m,表示 A 國有 n 座城市和 m 條道
路。
接下來 m 行每行 3 個整數 x、 y、 z,每兩個整數之間用一個空格隔開,表示從 x 號城市到 y 號城市有一條限重為 z 的道路。意:x 不等於 y,兩座城市之間可能有多條道路。
接下來一行有一個整數 q,表示有 q 輛貨車需要運貨。
接下來 q 行,每行兩個整數 x、y,之間用一個空格隔開,表示一輛貨車需要從 x 城市運輸貨物到 y 城市,注意:x 不等於 y。
輸出檔名為 truck.out。
輸出共有 q 行,每行一個整數,表示對於每一輛貨車,它的最大載重是多少。如果貨
車不能到達目的地,輸出-1。
輸入輸出樣例
輸入樣例#1:4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
輸出樣例#1:3
-1
3
說明
對於 30%的資料,0 < n < 1,000,0 < m < 10,000,0 < q< 1,000; 對於 60%的資料,0 < n < 1,000,0 < m < 50,000,0 < q< 1,000; 對於 100%的資料,0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,000。【思路】kruskal求最大生成樹,發現加入一條邊使x,y聯通,則該條邊的權值為所求。易證。
有一個巧妙的想法,因為邊是由大到小加進來的,所以越往上的祖先所管的邊權越小,因此我們只要跑一下最大生成樹再跑lca便可求解。
【程式碼】<span style="font-size:18px;">#include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int maxn=100005; struct data{ int u,v,w; bool operator <(const data&b)const{ return(w>b.w); } }e[maxn]; int q,n,m,anc[maxn],fa[maxn],cnt=1,num,dep[maxn],f[maxn][19],val[maxn]; inline int get(){ char c;while(!isdigit(c=getchar())); int p=c-48;while(isdigit(c=getchar()))p=p*10+c-48; return p; } inline int lca(int a,int b){ if(dep[a]<dep[b])swap(a,b); int j=0; while((1<<(j+1))<=dep[a])++j; for(int i=j;i>=0;--i){ //注意i可以取零 if((dep[a]-(1<<i))>=dep[b])a=f[a][i]; } if(a==b)return a; for(int i=j;i>=0;--i){ if(f[a][i] && f[a][i]!=f[b][i]){ a=f[a][i]; b=f[b][i]; } } return fa[a]; } inline int Find(int x){ if(x==anc[x])return anc[x]; else return (anc[x]=Find(anc[x])); } int main(){ memset(f,0,sizeof(f)); memset(fa,0,sizeof(fa)); n=get();m=get(); for(int i=1;i<=m;++i)e[i].u=get(),e[i].v=get(),e[i].w=get(); sort(e+1,e+1+m);num=n; for(int i=1;i<=n;++i)anc[i]=i; for(int i=1;i<=m;++i){ int x=Find(anc[e[i].u]); int y=Find(anc[e[i].v]); if(x!=y){ anc[x]=anc[y]=fa[x]=fa[y]=++n; //想象一下 fa[n]=0,val[n]=e[i].w,anc[n]=n; ++cnt;if(cnt==num)break; } } dep[n]=0; for(int i=n-1;i;--i){ dep[i]=dep[fa[i]]+1; f[i][0]=fa[i]; int j=1; while(f[f[i][j-1]][j-1])f[i][j]=f[f[i][j-1]][j-1],++j; } q=get(); while(q--){ int x=get(),y=get(); if(Find(x)!=Find(y))printf("-1\n"); else printf("%d\n",val[lca(x,y)]); } return 0; }</span>