1. 程式人生 > >【NOIP 2013】貨車運輸 倍增+kruskal

【NOIP 2013】貨車運輸 倍增+kruskal

題目描述 Description
A 國有 n 座城市,編號從 1 到 n,城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 q 輛貨車在運輸貨物,司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。

輸入描述 Input Description
第一行有兩個用一個空格隔開的整數 n,m,表示 A 國有 n 座城市和 m 條道路。
接下來 m 行每行 3 個整數 x、y、z,每兩個整數之間用一個空格隔開,表示從 x 號城市到 y 號城市有一條限重為 z 的道路。注意:x 不等於 y,兩座城市之間可能有多條道路。
接下來一行有一個整數 q,表示有 q 輛貨車需要運貨。
接下來 q 行,每行兩個整數 x、y,之間用一個空格隔開,表示一輛貨車需要從 x 城市運輸貨物到 y 城市,注意:x 不等於 y。

輸出描述 Output Description
輸出共有 q 行,每行一個整數,表示對於每一輛貨車,它的最大載重是多少。如果貨車不能到達目的地,輸出-1。

樣例輸入 Sample Input

4 3 
1 2 4 
2 3 3 
3 1 1 
3
1 3 
1 4 
1 3

樣例輸出 Sample Output

3
-1
3

資料範圍及提示 Data Size & Hint

對於 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,跑一遍最大生成樹,然後我們在這個最大生成樹上面跑倍增,並且維護兩點的之間的最小值。
證明:
為什麼在最大生成樹上跑倍增就可以了呢?因為若我們跑的是最大生成樹這樣的話,這樣樹上任意兩點之間的最短路一定大於或等於其他連線這兩點的路徑的值。

#include <algorithm>
#include <iostream>
#include <cstring> 
#include <cstdio> #include <string> using namespace std; const int MAXN = 10005,MAXX = 5000005,MAXD = 20; int head[MAXN],Fa[MAXN],deep[MAXN],Min[MAXN][23],anc[MAXN][23]; int T,N,M,e = 1,sum,dist; struct node{ int v,c,next; }edge[MAXX]; struct ABC{ friend bool operator < (const ABC &a,const ABC &b){ return a.c > b.c; } int u,v,c; }Tree[MAXX]; inline void addedge(int u,int v,int c){ edge[e] = {v,c,head[u]};head[u] = e++; edge[e] = {u,c,head[v]};head[v] = e++; } inline int read() { int x = 0;char ch = getchar(); while(ch < '0' || '9' < ch){ch = getchar();} while('0' <= ch && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x; } int Find_set(int x){ return Fa[x] == x ? x : Fa[x] = Find_set(Fa[x]);} inline void Union(int x,int y,int c){ int fx = Find_set(x); int fy = Find_set(y); Fa[fx] = fy; addedge(x,y,c); } void dfs(int u,int h){ deep[u] = h; for(int i = 1;i <= MAXD;i++){ anc[u][i] = anc[ anc[u][i-1] ][i-1]; Min[u][i] = min( Min[ anc[u][i-1] ][i-1] , Min[u][i-1] ); } for(int i = head[u];i;i = edge[i].next){ int v = edge[i].v,c = edge[i].c; if(!deep[v]){ anc[v][0] = u; Min[v][0] = c; dfs(v,h+1); } } } inline int swim(int &u,int v){ dist = 1100000; for(int i = MAXD;i >= 0;i--) if(deep[anc[u][i]] > deep[v]){ dist = min(dist,Min[u][i]); u = anc[u][i]; } if(deep[u] != deep[v]){ dist = min(dist,Min[u][0]); u = anc[u][0]; } return dist; } inline void query(int x,int y){ dist = 1100000; if(deep[x] < deep[y]) swap(x,y); dist = min(dist,swim(x,y)); if(x == y) return; for(int i = MAXD;i >= 0;i--) if(anc[x][i] != anc[y][i]){ dist = min(Min[x][i],dist); dist = min(Min[y][i],dist); x = anc[x][i]; y = anc[y][i]; } if(x != y) dist = min( dist , min( Min[x][0] , Min[y][0] ) ); } inline void init() { N = read();M = read(); for(int i = 1;i <= M;i++){ Tree[i].u = read(); Tree[i].v = read(); Tree[i].c = read(); } for(int i = 1;i <= N;i++) Fa[i] = i; sort(Tree+1,Tree+1+M); for(int i = 1;i <= M;i++) { if(Find_set(Tree[i].u) != Find_set(Tree[i].v)) Union(Tree[i].u,Tree[i].v,Tree[i].c); } dfs(1,1); int Q = read();int U,V; for(int i = 1;i <= Q;i++){ U = read();V = read(); if(Find_set(U) == Find_set(V)) query(U,V),printf("%d\n",dist); else printf("-1\n"); } } int main() { init(); return 0; }