题目描述
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入输出格式
输入格式:
输入文件名为 truck.in。
输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x、 y、 z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路 。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: x 不等于 y 。
输出格式:
输出文件名为 truck.out。
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货
车不能到达目的地,输出-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%的数据,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。
Analysis
刷对一道这种题都要高歌欢呼了
题目描述很容易让人想到网络流(然而我连网络流都没想到),但是有多组询问,n还贼大,否决
有个显而易见的东西,对于多条边我们只需要保留容量最大的一条,但是邻接矩阵又会MLE
然后有个东西叫做最大生成树(森林),利用这个我们就能构造一张新的连通图(生成树),且边权(容量限制)是尽可能大的
考虑到题目分类是倍增,那么就倍增lca。除了原本的dp数组表示祖先,另开一个数组c,c[i][j]表示i与dp[i][j]之间的限制最小值
嗯,倍增还是忘了(noip阴影),网络流还是不太熟练。。
Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#define debug puts("-----")
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define fill(x, t) memset(x, t, sizeof(x))
#define PI (acos(-1.0))
#define EPS (1e-8)
#define INF (1<<30)
#define ll long long
#define db double
#define ld long double
#define pb push_back
#define N 10001
#define E N * 8 + 1
#define MOD 100000007
#define L 255
using namespace std;
struct edge{int x, y, w, vis, next;}e[E];
int acs[N][17], c[N][17], d[N], ls[N], fa[N];
inline int read(){
int x = 0, v = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-'){
v = -1;
}
ch = getchar();
}
while (ch <= '9' && ch >= '0'){
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return x * v;
}
inline int addEdge(int &cnt, const int &x, const int &y, int w = 1){
e[++ cnt] = (edge){x, y, w, 0, ls[x]}; ls[x] = cnt;
return 0;
}
inline int cmp(const edge &a, const edge &b){
return a.w > b.w;
}
inline int getFather(const int &now){
return now == fa[now]? now: fa[now] = getFather(fa[now]);
}
inline int merge(const int &x, const int &y){
int fx = getFather(x), fy = getFather(y);
if (fx ^ fy){
fa[fx] = fy;
return 1;
}
return 0;
}
inline int kruskal(const int &n, const int &edgeCnt){
rep(i, 1, n){
fa[i] = i;
}
sort(e + 1, e + edgeCnt + 1, cmp);
int tot = 0, cnt = 0;
rep(i, 1, edgeCnt){
if (merge(e[i].x, e[i].y)){
tot += e[i].w;
cnt += 1;
e[i].vis = 1;
}
if (cnt == n - 1){
break;
}
}
if (cnt < n - 1){
tot = -1;
}
return tot;
}
inline int dfs(const int &now, const int &dep){
d[now] = dep;
// printf("now = %d\n", now);
for (int i = ls[now]; i; i = e[i].next){
if (!d[e[i].y]){
acs[e[i].y][0] = now;
c[e[i].y][0] = e[i].w;
rep(j, 1, 16){
acs[e[i].y][j] = acs[acs[e[i].y][j - 1]][j - 1];
c[e[i].y][j] = min(c[e[i].y][j - 1], c[acs[e[i].y][j - 1]][j - 1]);
}
dfs(e[i].y, dep + 1);
}
}
}
inline int min(const int &x, const int &y){
return x<y?x:y;
}
inline int lca(const int &l, const int &r){
int x = l, y = r;
int cx = INF, cy = INF;
if (d[x] < d[y]){
x ^= y;
y ^= x;
x ^= y;
}
drp(i, 16, 0){
if (d[acs[x][i]] >= d[y]){
cx = min(cx, c[x][i]);
x = acs[x][i];
}
}
if (x == y){
return cx;
}
drp(i, 16, 0){
if (acs[x][i] ^ acs[y][i]){
cx = min(cx, c[x][i]);
x = acs[x][i];
cy = min(cy, c[y][i]);
y = acs[y][i];
}
}
return min(min(min(cx, cy), c[x][0]), c[y][0]);
}
int main(void){
int n = read(), m = read();
int edgeCnt = 0;
rep(i, 1, m){
int x = read(), y = read(), w = read();
addEdge(edgeCnt, x, y, w);
}
kruskal(n, edgeCnt);
vector<int> x, y, w;
rep(i, 1, edgeCnt){
if (e[i].vis){
x.pb(e[i].x);
y.pb(e[i].y);
w.pb(e[i].w);
// printf("%d, %d, %d\n", e[i].x, e[i].y, e[i].w);
}
}
fill(ls, 0);
edgeCnt = 0;
rep(i, 0, x.size() - 1){
addEdge(edgeCnt, x[i], y[i], w[i]);
addEdge(edgeCnt, y[i], x[i], w[i]);
}
dfs(1, 1);
int q = read();
rep(i, 1, q){
int st = read(), ed = read();
int ans = lca(st, ed);
if (!ans){
ans = -1;
}
printf("%d\n", ans);
}
return 0;
}