题目链接:Vlad and the Mountains
由题意我们可知,从u到v不管怎么走,山的高度始终不能超过h(st)+e,那么问题就转化为了给定q次询问,是否存在一条路径,使得从u到v的所有点的高度不超过h(u)+e。那么就可以考虑并查集,将所有点<=h(u)+e合并然后判断是否连通。
那么一次次枚举询问显然会超时,那么可以采用离线询问的方式去解决:
首先记录每次询问,然后根据h(u)+e的大小从小到大排序,同时对山峰的高度进行排序,那么高度从小到大将一个个点连通不影响结果。
代码附上:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5+5;
int h[N],b[N],pre[N],ans[N],vis[N];
vector<int>g[N];
struct node{int u,v,e,id;
}q[N];
int n,m,que;int cmp(node a,node b){return h[a.u]+a.e<h[b.u]+b.e;
}int cmp1(int a,int b){return h[a]<h[b];
}int root(int x){return pre[x]=(pre[x]==x)?x:root(pre[x]);
}void init(){for(int i=1;i<=n;i++){pre[i]=i;b[i]=i;g[i].clear();h[i]=ans[i]=vis[i]=0;}
}void solve(){cin>>n>>m;init();for(int i=1;i<=n;i++)cin>>h[i];for(int i=1;i<=m;i++){int x,y;cin>>x>>y;g[x].push_back(y);g[y].push_back(x);}cin>>que;for(int i=1;i<=que;i++){//离线询问cin>>q[i].u>>q[i].v>>q[i].e;q[i].id=i;}sort(q+1,q+1+que,cmp);//对询问的初始高度排序sort(b+1,b+1+n,cmp1);//对山峰的高度排序(索引)int j=1;for(int i=1;i<=que;i++){for(;j<=n;j++){if(h[b[j]]>h[q[i].u]+q[i].e)break;//如果高度超出vis[b[j]]=1;for(const auto &y:g[b[j]]){//判断两点是否能连通if(vis[y]){int fx=root(b[j]);int fy=root(y);if(fx!=fy)pre[fx]=fy;}}}ans[q[i].id]=(root(q[i].u)==root(q[i].v));}for(int i=1;i<=que;i++){if(ans[i])cout<<"YES"<<"\n";else cout<<"NO"<<"\n";}cout<<"\n";return;}signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int t;cin>>t;while(t--){solve();}return 0;
}