?
試題描述 |
A 國有n座城市,編號從1到n,城市之間有m條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有q輛貨車在運輸貨物,司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。 |
輸入 |
第一行有兩個用一個空格隔開的整數n,m,表示A國有n座城市和m條道路。接下來m行每行3個整數x、y、z,每兩個整數之間用一個空格隔開,表示從x號城市到y號城市有一條限重為z的道路。注意:x不等于y,兩座城市之間可能有多條道路。接下來一行有一個整數q,表示有q輛貨車需要運貨。接下來q行,每行兩個整數x、y,之間用一個空格隔開,表示一輛貨車需要從x城市運輸貨物到y城市,注意:x不等于y。 |
輸出 |
共有q行,每行一個整數,表示對于每一輛貨車,它的最大載重是多少。如果貨車不能到達目的地,輸出-1。 |
輸入示例 |
4?3 1?2?4 2?3?3 3?1?1 3 1?3 1?4 1?3 |
輸出示例 |
3 -1 3 |
其他說明 |
數據范圍:0<n<10,000,0<m<50,000,0<q<30,000,0≤z≤100,000。 |
這里用了某神犇論文中的解法。
首先做一遍最大生成樹,那么問題轉化成了樹上路徑查詢最小值,我們考慮用按秩合并的并查集來做。
做最大生成樹當合并節點(x,y)時,考慮將x的fa設為y,并記錄v[x]=e[i].w。
那么詢問時我們先判斷兩點是否在同一連通分量中,然后因為按秩合并的樹高最多是logn的,暴力向上找并更新答案即可。


#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(s,t) for(int i=s;i<=t;i++) #define ren for(int i=first[x];i!=-1;i=next[i]) using namespace std; inline int read() {int x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f; } const int maxn=50010; struct Edge {int u,v,w;bool operator < (const Edge& ths) const {return w>ths.w;} }e[maxn]; int n,m,q,pa[maxn],rk[maxn],v[maxn]; int findset(int x) {return x==pa[x]?x:findset(pa[x]);} int get(int x,int& d) {if(x==pa[x]) return x;d++;return get(pa[x],d); } int main() {n=read();m=read();rep(1,n) pa[i]=i;rep(1,m) e[i].u=read(),e[i].v=read(),e[i].w=read();sort(e+1,e+m+1);rep(1,m) {int x=findset(e[i].u),y=findset(e[i].v);if(x!=y) {if(rk[x]>rk[y]) swap(x,y);pa[x]=y;v[x]=e[i].w;if(rk[x]==rk[y]) rk[y]++;}}q=read();while(q--) {int d1=0,d2=0,ans=1e9;int x=read(),y=read();if(get(x,d1)==get(y,d2)) {if(d1<d2) swap(x,y),swap(d1,d2);rep(1,d1-d2) ans=min(ans,v[x]),x=pa[x];while(x!=y) {ans=min(ans,min(v[x],v[y]));x=pa[x];y=pa[y];}printf("%d\n",ans);}else puts("-1");}return 0; }
?