您现在的位置是:首页 >学无止境 >货车运输 kruskal重构树+倍增lca维护路径最小值网站首页学无止境
货车运输 kruskal重构树+倍增lca维护路径最小值
[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
eq 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 eq 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 1le 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 imes 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 imes 10^4 1≤m<5×104,$1 le q< 3 imes 10^4 $, 0 ≤ z ≤ 1 0 5 0 le z le 10^5 0≤z≤105。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct Edge{
int a,b;
int w;
bool operator<(const Edge&W)const{
return w>W.w;
}
}edge[N];
int p[N];
int e[N],ne[2*N],w[2*N],h[2*N],idx;
int fa[N][20];
int minw[N][20];
int depth[N];
int n,m;
int T;
int res;
bool st[N];
int find(int x){
if(x!=p[x]) p[x] = find(p[x]);
return p[x];
}
void add(int a,int b,int c){
e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a]=idx++;
}
void dfs(int u,int father){
st[u] = 1;
depth[u] = depth[father] + 1;
fa[u][0] = father;
for(int i=1;i<=17;i++){
fa[u][i] = fa[fa[u][i-1]][i-1];
minw[u][i] = min(minw[fa[u][i-1]][i-1],minw[u][i-1]);
}
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(j!=father)
{
minw[j][0] = w[i];
dfs(j,u);
}
}
}
int lca(int a,int b){
int res = 0x3f3f3f3f;
if(depth[a]<depth[b])swap(a,b);
for(int i=17;i>=0;i--)
if(depth[fa[a][i]]>=depth[b]){
res = min(res,minw[a][i]);
a = fa[a][i];
}
if(a==b)return res;
for(int i=17;i>=0;i--)
if(fa[a][i]!=fa[b][i]){
res = min(res,minw[a][i]);
res = min(res,minw[b][i]);
a = fa[a][i],b = fa[b][i];
}
res = min(res,minw[a][0]);
res = min(res,minw[b][0]);
return res;
}
void init()
{
cin>>n>>m;
for(int i=1;i<=m;i++)cin>>edge[i].a>>edge[i].b>>edge[i].w;
for(int i=1;i<=n;i++)p[i] = i;
memset(h,-1,sizeof h);
memset(minw,0x3f,sizeof minw);
sort(edge+1,edge+m+1);
for(int i=1;i<=m;i++){
int a = edge[i].a,b=edge[i].b,w=edge[i].w;
if(find(a)!=find(b)){
add(a,b,w),add(b,a,w);
//printf("%d %d %d
",a,b,w);
p[find(a)] = find(b);
}
}
for(int i=1;i<=n;i++)
if(!st[i]){
dfs(i,0);
// printf("%d
",i);
st[i] = 1;
}
//printf("%d ",minw[4][0]);
}
void solve()
{
int a,b;
cin>>a>>b;
if(find(a)!=find(b)){//不连通
puts("-1");
return;
}
cout<<lca(a,b)<<endl;
}
int main()
{
init();
cin>>T;
while(T--)solve();
}
想明白贪心的思路,先维护一棵最大生成树然后自己维护一下倍增lca路径最小值就行了