G. Vlad and the Mountains

发布时间 2023-10-07 14:58:41作者: 不o凡

G. Vlad and the Mountains

题意:给你每个点的高度,从a到b需要消耗h[b]-h[a]的体力值(所以说下坡时体力值可以增加),询问一开始你有e的体力值,问是否可以从u->v点

分析:
1.a->b最终消耗的体力值一定为h[b]-h[a],如果一开始的体力值都达不到肯定无法过
2.如果期间高度大于h[a]+c,那么也是过不了的

方法:
1.我们对加边取最高点进行排序,原因:高度越小越可能爬到
2.对询问进行离线处理,并对其以h[a]+e进行排序,原因:如果加边的权值小于询问的最大值,那么两点在此高度下可以到达,将其加入并查集中
3.因为询问能到达的最大高度是递增的,所以后续不影响,如果询问的两点在并查集中,说明可以到达,反之不行

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int h[N];
struct node{
	int u,v,w,id;
}a[N],qry[N];
bool cmp(node a,node b){
	return a.w<b.w;
}
int f[N];
int find(int x){
	return f[x]==x?x:f[x]=find(f[x]);
}
int ans[N];
void solve(){
	int n,m;
	cin>>n>>m;
	memset(ans,0,sizeof ans);
	for(int i=1;i<=n;i++) f[i]=i;//并查集
	for(int i=1;i<=n;i++) cin>>h[i];
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		int w=max(h[u],h[v]);//记录最高值
		a[i].u=u;a[i].v=v;a[i].w=w;
	}
	sort(a+1,a+1+m,cmp);
	int q;
	cin>>q;
	for(int i=1;i<=q;i++){
		int a,b,c;
		cin>>a>>b>>c;
		qry[i].u=a;
		qry[i].v=b;
		qry[i].w=h[a]+c;//h[a]+c可以到达的最高高度
		qry[i].id=i;//离线查询
	}
	sort(qry+1,qry+1+q,cmp);
	int p=1;
	for(int i=1;i<=q;i++){
		while(p<=m&&qry[i].w>=a[p].w){//加边,如果高度小于能到达的查询高度,说明可以
			int x=find(a[p].v);
			int y=find(a[p].u);
			if(x!=y){
				f[x]=y;
			}
			p++;
		}
		if(find(qry[i].u)==find(qry[i].v)) ans[qry[i].id]=1;//如果两者在并查集里面,说明两者连同
	}
	for(int i=1;i<=q;i++){
		if(ans[i]) cout<<"YES\n";
		else cout<<"NO\n";
	}
	cout<<'\n';
}
int main(){
	int t;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}