【题解】CF1550F Jumping Around

题意

给定一个序列 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<=n;i++) { // printf("dp[%d]=%d\n",i,dp[i]); // } for(int i=1;i<=m;i++) { int x; scanf("%d%d",&x,&k); printf("%s\n",(k>=dp[x])?"yes":"no"); } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530310.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示