[NOIP2013 提高组] 货车运输
题目描述
A 国有 n n n 座城市,编号从 1 1 1 到 n n n,城市之间有 m m m 条双向道路。每一条道路对车辆都有重量限制,简称限重。
现在有 q q q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入格式
第一行有两个用一个空格隔开的整数 $ n,m$,表示 A 国有 $ n$ 座城市和 m m m 条道路。
接下来
m
m
m 行每行三个整数
x
,
y
,
z
x, y, z
x,y,z,每两个整数之间用一个空格隔开,表示从 $x $ 号城市到 $ y $ 号城市有一条限重为
z
z
z 的道路。
注意:
x
≠
y
x \neq y
x=y,两座城市之间可能有多条道路 。
接下来一行有一个整数 q q q,表示有 q q q 辆货车需要运货。
接下来 q q q 行,每行两个整数 x , y x,y x,y,之间用一个空格隔开,表示一辆货车需要从 x x x 城市运输货物到 y y y 城市,保证 x ≠ y x \neq y x=y
输出格式
共有
q
q
q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。
如果货车不能到达目的地,输出
−
1
-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% 的数据, 1 ≤ n < 1000 1 \le n < 1000 1≤n<1000, 1 ≤ m < 10 , 000 1 \le m < 10,000 1≤m<10,000, 1 ≤ q < 1000 1\le q< 1000 1≤q<1000;
对于 60 % 60\% 60% 的数据, 1 ≤ n < 1000 1 \le n < 1000 1≤n<1000, 1 ≤ m < 5 × 1 0 4 1 \le m < 5\times 10^4 1≤m<5×104, 1 ≤ q < 1000 1 \le q< 1000 1≤q<1000;
对于 100 % 100\% 100% 的数据, 1 ≤ n < 1 0 4 1 \le n < 10^4 1≤n<104, 1 ≤ m < 5 × 1 0 4 1 \le m < 5\times 10^4 1≤m<5×104,$1 \le q< 3\times 10^4 $, 0 ≤ z ≤ 1 0 5 0 \le z \le 10^5 0≤z≤105。
解析:
题目询问路径上边权最小值。
按照最大生成树的顺序建立克鲁斯卡尔重构树,则路径上最小边权是重构树上lca的点权。树剖或者倍增求lca
关于克鲁斯卡尔重构树,给自己打个广告
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
const int maxn = 2e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
int head[maxn], tot;
struct edge{
int to, nxt;
}e[maxn];
struct node{
int x, y, w;
node(){}
node(int x, int y, int w): x(x), y(y), w(w){}
bool operator < (const node &b) const{
return w > b.w;
}
}edg[maxn];
void add(int a, int b){
e[++tot].nxt = head[a];
e[tot].to = b;
head[a] = tot;
}
int n, m, q;
int siz[maxn], p[maxn], son[maxn], dep[maxn], top[maxn];
int vis[maxn];
int fa[maxn];
int find(int x){
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void dfs1(int u, int pa){
siz[u] = 1;
vis[u] = 1;
dep[u] = dep[pa] + 1;
p[u] = pa;
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v == pa)
continue;
dfs1(v, u);
if(siz[son[u]] < siz[v]);
son[u] = v;
siz[u] += siz[v];
}
}
void dfs2(int u, int tp){
top[u] = tp;
if(son[u])
dfs2(son[u], tp);
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v == son[u] || v == p[u])
continue;
dfs2(v, v);
}
}
int LCA(int a, int b){
while(top[a] != top[b]){
if(dep[top[a]] > dep[top[b]])
a = p[top[a]];
else
b = p[top[b]];
}
return dep[a] > dep[b] ? b : a;
}
int nodetot;
int val[maxn];
void solve(){
cin >> n >> m;
for(int i = 1; i <= n; i++)
fa[i] = i;
for(int i = 1; i <= m; i++){
int x, y, z;
cin >> x >> y >> z;
edg[i] = node(x, y, z);
}
nodetot = n;
sort(edg+1, edg+m+1);
for(int i = 1; i <= m; i++){
int fx = find(edg[i].x);
int fy = find(edg[i].y);
if(fx == fy)
continue;
val[++nodetot] = edg[i].w;
fa[nodetot] = fa[fx] = fa[fy] = nodetot;
add(nodetot, fx); add(nodetot, fy);
add(fx, nodetot); add(fy, nodetot);
}
for(int i = 1; i <= nodetot; i++){
if(!vis[i]){
int fx = find(i);
dfs1(fx, 0);
dfs2(fx, fx);
}
}
cin >> q;
for(int i = 1; i <= q; i++){
int x, y;
cin >> x >> y;
int fx = find(x);
int fy = find(y);
if(fx != fy)
cout << -1 << endl;
else{
int lca = LCA(x, y);
cout << val[lca] << endl;
}
}
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T = 1;
while(T--)
solve();
return 0;
}