1. 程式人生 > >[Noip2013] 貨車運輸

[Noip2013] 貨車運輸

不能 mem 輸出 align 編號 pan font 兩個 多重

題目描述

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-11。

輸入輸出樣例

輸入樣例#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,0z100,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] 貨車運輸