题目描述
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。
输入输出样例
说明
对于 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; }