题意
给定一个序列 a[]
和初始起点 s
,每次从 i
位置跳跃到 j
要满足 d-k<=abs(a[i]-a[j])<=d+k
,每次询问给出 k
和目的位置 x
,询问是否可行。
n,m<=2e5
。
Solution:
从定义想到连边。那么本题就是求最小生成树。边数为 n^2
,考虑 boruvka 算法
。
算法流程:维护若干连通块,然后对于每个连通块向其他连出代价最小的边,迭代上述过程。
算法证明:只需证明连出的边一定在 MST
树上。假设不在,那么一定存在一个环满足当前边最大,但是当前边是所有连出去的边中最小的边,所以假设不成立。
可以证明,经过一次连边后,仍然会形成若干连通块,且连通块的个数至少减少一半。时间复杂度为 O(mlogn)
。
回到本题。显然我们不会枚举所有边,而是用 set
模拟,时间复杂度 O(nlog^2n)
。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define PII pair<int,int>
#define All(a) a.begin(),a.end()
#define F(x) abs(a[x]+d-it->first)
#define G(x) abs(a[x]-d-it->first)
using namespace std;
const int mx=2e5+5;
int n,m,cnt,a[mx],bl[mx],dp[mx],fa[mx],vis[mx],s,d,k;
set<PII> A;
vector<PII> g[mx];
vector<int> f[mx];
void dfs(int x,int fa) {
for(auto y:g[x]) {
if(vis[y.first]) continue; vis[y.first]=1;
dp[y.first]=max(dp[x],y.second);
dfs(y.first,x);
}
}
int find(int x) {
return (fa[x]==x)?x:fa[x]=find(fa[x]);
}
void unionset(int x,int y) {
int u=find(x),v=find(y);
if(u!=v) fa[u]=v;
}
void Boruvka() {
for(int i=1;i<=n;i++) bl[i]=i,fa[i]=i; cnt=n;
while(cnt>1) {
A.clear(); for(int i=1;i<=n;i++) vis[i]=0;
for(int i=1;i<=n;i++) A.insert(make_pair(a[i],i));
for(int i=1;i<=cnt;i++) f[i].clear();
for(int i=1;i<=n;i++) f[bl[i]].push_back(i);
for(int i=1;i<=cnt;i++) {
for(auto x:f[i]) {
A.erase(make_pair(a[x],x));
}
int u(0),v(0),Min=INF;
for(auto x:f[i]) {
auto it=A.lower_bound(make_pair(a[x]+d,0));
if(it!=A.end() && F(x) < Min) {
Min = F(x);
u = x; v = it->second;
}
if(it--!=A.begin() && F(x) < Min) {
Min = F(x);
u = x; v = it->second;
}
it=A.lower_bound(make_pair(a[x]-d,0));
if(it!=A.end() && G(x) < Min) {
Min = G(x);
u = x; v = it->second;
}
if(it--!=A.begin() && G(x) < Min) {
Min = G(x);
u = x; v = it->second;
}
}
unionset(u,v); g[u].push_back(make_pair(v,Min)),g[v].push_back(make_pair(u,Min));
for(auto x:f[i]) {
A.insert(make_pair(a[x],x));
}
}
cnt=0;
for(int i=1;i<=n;i++) {
if(!vis[find(i)]) {
vis[find(i)]=++cnt;
}
bl[i]=vis[find(i)];
}
}
}
int main() {
scanf("%d%d%d%d",&n,&m,&s,&d);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
Boruvka();
memset(vis,0,sizeof(vis)),vis[s]=1,dfs(s,0);
for(int i=1;i<=m;i++) {
int x; scanf("%d%d",&x,&k);
printf("%s\n",(k>=dp[x])?"yes":"no");
}
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」