[Noip2013] 貨車運輸
題目描述
AAA國有nn n座城市,編號從 11 1到n nn,城市之間有 mmm 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 qqq 輛貨車在運輸貨物, 司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。
輸入輸出格式
輸入格式:第一行有兩個用一個空格隔開的整數n,m n,mn,m,表示 AAA 國有n nn 座城市和 mmm 條道路。
接下來 mmm行每行3 3 3個整數 x,y,zx, y, zx,y,z,每兩個整數之間用一個空格隔開,表示從 xx x號城市到y y y號城市有一條限重為 zzz 的道路。註意: xxx 不等於 yyy,兩座城市之間可能有多條道路
接下來一行有一個整數 q,表示有 q 輛貨車需要運貨。
接下來 q 行,每行兩個整數 x、y,之間用一個空格隔開,表示一輛貨車需要從 x 城市運輸貨物到 y 城市,註意: x 不等於 y 。
輸出格式:共有 qqq 行,每行一個整數,表示對於每一輛貨車,它的最大載重是多少。如果貨車不能到達目的地,輸出−1-1−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%30\%30%的數據,0<n<1,000,0<m<10,000,0<q<1,0000 < n < 1,000,0 < m < 10,000,0 < q< 1,0000<n<1,000,0<m<10,000,0<q<1,000;
對於 60%60\%60%的數據,0<n<1,000,0<m<50,000,0<q<1,0000 < n < 1,000,0 < m < 50,000,0 < q< 1,0000<n<1,000,0<m<50,000,0<q<1,000;
對於 100%100\%100%的數據,0<n<10,000,0<m<50,000,0<q<30,000,0≤z≤100,0000 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,0000<n<10,000,0<m<50,000,0<q<30,000,0≤z≤100,000。
說實話這題很容易想到,像我這樣的蒟蒻都能想到...
顯然有一些邊是沒有用的,我們只需要保證圖聯通就行了,所以自然而然的想到生成樹。
所以求一遍最大生成樹,然後後面的直接類似倍增找LCA一樣的寫就行了,十分簡單。
有個坑點,圖不一定聯通(廢話,要不為什麽輸出-1)。
然而數據有在一個聯通塊裏的, 我預處理的時候只從1開始bfs,這樣gg了,必須從所有聯通塊都處理一遍。
輕松A掉。
#include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <cstring> using namespace std; #define reg register #define N 10005 #define M 50005 inline int read() { int res=0;char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return res; } int n, m; struct edge { int nxt, to, val, from; }ed[M*2]; int cnt = 1, head[N]; inline void add(int x, int y, int z) { ed[++cnt] = (edge){head[x], y, z, x}; head[x] = cnt; } struct date { int x, y, id, val; }dat[M]; inline bool cmp(date a, date b) { return a.val > b.val; } int fa[N]; int Find(int x) {return fa[x]==x?x:fa[x]=Find(fa[x]);} int fu[N][20], mn[N][20]; int dep[N]; bool vis[N]; inline void bfs(int cur) { queue <int> q; q.push(cur); dep[cur] = 1; vis[cur] = 1; while(!q.empty()) { int x = q.front();q.pop(); for (reg int i = head[x] ; i ; i = ed[i].nxt) { int to = ed[i].to; if (vis[to]) continue; vis[to] = 1; dep[to] = dep[x] + 1; fu[to][0] = x; mn[to][0] = ed[i].val; for (reg int j = 1 ; j <= 19 ; j ++) fu[to][j] = fu[fu[to][j-1]][j-1], mn[to][j] = min(mn[to][j-1], mn[fu[to][j-1]][j-1]); q.push(to); } } } inline int solve(int x, int y) { int res = 1e9; if (dep[x] < dep[y]) swap(x, y); for (reg int i = 19 ; i >= 0 ; i --) if (dep[fu[x][i]] >= dep[y]) res = min(res, mn[x][i]), x = fu[x][i]; if (x == y) return res; for (reg int i = 19 ; i >= 0 ; i --) if (fu[x][i] != fu[y][i]) res = min(res, min(mn[x][i], mn[y][i])), x = fu[x][i], y = fu[y][i]; res = min(res, min(mn[x][0], mn[y][0])); return res; } int main() { n = read(), m = read(); for (reg int i = 1 ; i <= m ; i ++) { int x = read(), y = read(), z = read(); dat[i] = (date){x, y, i, z}; } sort(dat + 1, dat + 1 + m, cmp); int k = 0; for (reg int i = 1 ; i <= n ; i ++) fa[i] = i; for (reg int i = 1 ; i <= m ; i ++) { int x = dat[i].x, y = dat[i].y; int fx = Find(x), fy = Find(y); if (fx == fy) continue; add(x, y, dat[i].val), add(y, x, dat[i].val); fa[fx] = fy; k++; if (k == n - 1) break; } memset(mn, 0x3f, sizeof mn); for (reg int i = 1 ; i <= n ; i ++) if (!vis[i]) bfs(i); int q = read(); while(q--) { int x = read(), y = read(); if (Find(x) != Find(y)) {puts("-1"); continue;} printf("%d\n", solve(x, y)); } return 0; }
[Noip2013] 貨車運輸