試題描述:A 國有 n 座城市,編號從 1 到 n,城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。如今有 q 輛貨車在運輸貨物,司機們想知道每輛車在不超過車輛限重的狀況下,最多能運多重的貨物。ios
輸入描述:git
第一行有兩個用一個空格隔開的整數 n,m,表示 A 國有 n 座城市和 m 條道路。
接下來 m 行每行 3 個整數 x、y、z,每兩個整數之間用一個空格隔開,表示從 x 號城市到 y 號城市有一條限重爲 z 的道路。注意:x 不等於 y,兩座城市之間可能有多條道路。
接下來一行有一個整數 q,表示有 q 輛貨車須要運貨。
接下來 q 行,每行兩個整數 x、y,之間用一個空格隔開,表示一輛貨車須要從 x 城市運輸貨物到 y 城市,注意:x 不等於 y。ide
輸出描述:函數
輸出共有 q 行,每行一個整數,表示對於每一輛貨車,它的最大載重是多少。若是貨車不能到達目的地,輸出-1。spa
樣例輸入:code
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3blog
樣例輸出:get
3
-1
3it
數據範圍:io
對於 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。
題解:這道題其實就是讓咱們找一條路使得這條路上的最小值最大,由此咱們不難想到對任意的從u到v的一條咱們所需的路徑,必定是在這個圖的最大生成樹上,因此咱們能夠先構造最大生成樹。
對於任意一組(u,v)(從u到v)用並查集能夠判斷若是u、v的祖先不一樣,那就說明u、v之間沒有路
若是有路,咱們用lca(最近公共祖先)來進行判斷。假設u、v的lca是t,那麼最終咱們須要的答案就是min(u到t的最短路限重,v到t的最短路限重),這樣咱們這個題就直接ac了
AC代碼以下:
1 #include<iostream> 2 #include<cctype> 3 #include<algorithm> 4 #include<memory.h> 5 using namespace std; 6 const int MAXN=100000+10; 7 int n,m; 8 //------------------------- 9 void read(int &x){ 10 x=0;int f=1;char ch=getchar(); 11 for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 12 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0'; 13 x*=f; 14 }//讀入函數 15 //------------------------- 16 struct edge{ 17 int u,v,w; 18 edge(){u=0;v=0;w=0;} 19 }to[50010]; 20 bool operator < (edge a,edge b){return a.w>b.w;} 21 //------------------------- 22 int fa[10010]; 23 int find(int x){ 24 if(x==fa[x])return x; 25 return fa[x]=find(fa[x]); 26 }//並查集 27 //------------------------- 28 int v[MAXN],w[MAXN],first[MAXN],next[MAXN],e; 29 void AddEdge(int a,int b,int c){ 30 v[++e]=b; 31 w[e]=c; 32 next[e]=first[a]; 33 first[a]=e; 34 }//鄰接表 35 void MST(){//最大生成樹 36 int cnt=0; 37 sort(to+1,to+m+1); 38 for(int i=1;i<=n;i++)fa[i]=i; 39 for(int i=1;i<=m;i++){ 40 int p=find(fa[to[i].v]),q=find(fa[to[i].u]); 41 if(p!=q){ 42 fa[p]=q; 43 AddEdge(to[i].v,to[i].u,to[i].w); 44 AddEdge(to[i].u,to[i].v,to[i].w); 45 cnt++; 46 } 47 if(cnt==n-1)break; 48 } 49 } 50 //------------------------ 51 int parent[17][10010]; 52 int depth[10010]; 53 int dist[17][MAXN]; 54 bool vis[10010]; 55 void dfs(int x,int p,int d){ 56 vis[x]=1; 57 parent[0][x]=p; 58 depth[x]=d; 59 for(int i=first[x];i;i=next[i]){ 60 if(vis[v[i]])continue; 61 dist[0][v[i]]=w[i]; 62 dfs(v[i],x,d+1); 63 } 64 } 65 66 void init(){//初始化 67 for(int i=1;i<=n;i++)if(!vis[i])dfs(i,-1,0); 68 for(int k=0;k+1<=16;k++){ 69 for(int i=1;i<=n;i++){ 70 if(parent[k][i]<0)parent[k+1][i]=-1; 71 else parent[k+1][i]=parent[k][parent[k][i]]; 72 dist[k+1][i]=min(dist[k][parent[k][i]],dist[k][i]); 73 } 74 } 75 } 76 77 int lca(int x,int y){//最近公共祖先 78 if(depth[y]>depth[x])swap(x,y); 79 for(int k=0;k<=16;k++) 80 if((depth[x]-depth[y])>>k&1) 81 x=parent[k][x]; 82 if(x==y)return x; 83 for(int k=16;k>=0;k--){ 84 if(parent[k][x]!=parent[k][y]){ 85 x=parent[k][x]; 86 y=parent[k][y]; 87 } 88 } 89 return parent[0][x]; 90 } 91 //------------------------------ 92 int work(int x,int y){ 93 int u=lca(x,y); 94 int t1=depth[x]-depth[u]; 95 int t2=depth[y]-depth[u]; 96 int minn1=-1u>>1,minn2=-1u>>1; 97 for(int i=0;i<=16;i++){ 98 if((t1&(1<<i))){ 99 minn1=min(minn1,dist[i][x]); 100 x=parent[i][x]; 101 } 102 if(t2&(1<<i)){ 103 minn2=min(minn2,dist[i][y]); 104 y=parent[i][y]; 105 } 106 } 107 return min(minn1,minn2); 108 } 109 //------------------------------- 110 int main(){ 111 memset(dist,127/3,sizeof(dist)); 112 read(n);read(m); 113 for(int i=1;i<=m;i++){ 114 read(to[i].u); 115 read(to[i].v); 116 read(to[i].w); 117 } 118 MST(); 119 init(); 120 int q; 121 read(q); 122 while(q--){ 123 int x,y; 124 read(x);read(y); 125 if(find(x)!=find(y)){ 126 printf("-1\n"); 127 continue; 128 } 129 printf("%d\n",work(x,y)); 130 } 131 }