您现在的位置是:首页 >学无止境 >货车运输 kruskal重构树+倍增lca维护路径最小值网站首页学无止境

货车运输 kruskal重构树+倍增lca维护路径最小值

拉马努金的数列灬 2024-06-17 11:27:01
简介货车运输 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 1n<1000 1 ≤ m < 10 , 000 1 le m < 10,000 1m<10,000 1 ≤ q < 1000 1le q< 1000 1q<1000

对于 60 % 60\% 60% 的数据, 1 ≤ n < 1000 1 le n < 1000 1n<1000 1 ≤ m < 5 × 1 0 4 1 le m < 5 imes 10^4 1m<5×104 1 ≤ q < 1000 1 le q< 1000 1q<1000

对于 100 % 100\% 100% 的数据, 1 ≤ n < 1 0 4 1 le n < 10^4 1n<104 1 ≤ m < 5 × 1 0 4 1 le m < 5 imes 10^4 1m<5×104,$1 le q< 3 imes 10^4 $, 0 ≤ z ≤ 1 0 5 0 le z le 10^5 0z105

#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路径最小值就行了

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。