【题解】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");
	}
} 
posted @ 2021-07-28 15:03  仰望星空的蚂蚁  阅读(14)  评论(0)    收藏  举报  来源