[ARC149D] 的题解

思路很巧妙,首先,很明显,数轴上关于原点对称的一个点对,不论移动了多少次,都任然是对称的。

再看眼数据范围,发现其实点分布的比较紧,考虑直接将所有点看做一个整体(数轴上一个线段),然后依次移动。

关键的是,若这个整体横跨了原点的话,那么在原点的点就有答案了,对于剩下的部分,设在正半轴、负半轴的部分长度为 \(len1,len2\),若 \(len1>len2\),则将负半轴的部分对称到正半轴,他之后的位置相当于对称后的位置的相反数。

反之同理。

而这个不断对称的过程,我们可以用并查集解决,每个节点就表示初始所在的位置。由于要判断相反数,所以用带权并查集即可。

由于有负半轴,所以记得要把数轴上的位置转化到并查集上,细节较多。

#include<bits/stdc++.h>
#define int long long
#define m_p make_pair
#define p_b push_back
#define num first
#define color second
using namespace std;
inline int rd(){
	int x=0,f=1; char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if (ch=='-') f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
	return x*f;
}
const int N=3e5+5,M=1e6;
int a[N],D[N],n,m;
int fa[M*2+5],val[M*2+5];//0:一样,1:变化
int find(int x){
	if(fa[x]==x) return x;
	int dad=fa[x];
	fa[x]=find(fa[x]);
	val[x]^=val[dad];
	return fa[x];
}
int ans[M*2+5];
signed main(){
	n=rd(),m=rd();
	for(int i=1;i<=n;i++) a[i]=rd();
	for(int i=1;i<=m;i++) D[i]=rd();
	int l=a[1],r=a[n];//在数轴上的范围,并查集的范围
	for(int i=0;i<=(M<<1);i++) fa[i]=i;
	int x,fx;
	for(int i=1;i<=m;i++){
		if(l>0) l-=D[i],r-=D[i];
		else l+=D[i],r+=D[i];
		if(l<=0&&0<=r){//横跨了远点
			x=M;fx=find(x);
			ans[fx]=i;
			if(-l<r){//移动往正半轴
				for(int i=1;i<=-l;i++){
					fa[M-i]=M+i;
					val[M-i]^=1;
				}
				l=1;
			}
			else{
				for(int i=1;i<=r;i++){
					fa[M+i]=M-i;
					val[M+i]^=1;
				}
				r=-1;
			}
		}
	}
	int now;
	for(int i=1;i<=n;i++){
		x=find(a[i]+M);
		if(ans[x]) printf("Yes %lld\n",ans[x]);
		else{
			now=x-M;
			if(val[a[i]+M])now*=-1;
			printf("No %lld\n",now);
		}
	}
	return 0;
}
posted @ 2024-05-15 22:51  123456xwd  阅读(33)  评论(0)    收藏  举报