[ARC149D] 的题解
思路很巧妙,首先,很明显,数轴上关于原点对称的一个点对,不论移动了多少次,都任然是对称的。
再看眼数据范围,发现其实点分布的比较紧,考虑直接将所有点看做一个整体(数轴上一个线段),然后依次移动。
关键的是,若这个整体横跨了原点的话,那么在原点的点就有答案了,对于剩下的部分,设在正半轴、负半轴的部分长度为
反之同理。
而这个不断对称的过程,我们可以用并查集解决,每个节点就表示初始所在的位置。由于要判断相反数,所以用带权并查集即可。
由于有负半轴,所以记得要把数轴上的位置转化到并查集上,细节较多。
#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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】