题目链接
题目解法
首先可以观察到一个
s
i
m
p
l
e
simple
simple 的性质:两个相反数每次移动到的位置也是相反数
同时因为坐标的范围较小,所以可以考虑维护一部分位置的信息,来推出其他与它对称的点的信息
首先维护
l
,
r
l,r
l,r,表示当前只维护
l
−
r
l-r
l−r 的信息,同时维护
p
o
s
pos
pos 表示当前原点所在位置
考虑把位置的移动变成原点的移动,这样每个位置与原点的相对位置是不会发生改变的
如果原点在
l
,
r
l,r
l,r 之间,需分情况讨论
- r − p o s > p o s − l r-pos>pos-l r−pos>pos−l,即在原点右边的部分较大,考虑只维护原点右边的部分,舍弃原点左边的部分,只需要将右边的部分指向左边的部分,表示这两个点对称,答案相反即可
- r − p o s < = p o s − l r-pos<=pos-l r−pos<=pos−l,同理
最后考虑 x = p o s x=pos x=pos 的情况,即可以移到原点,只要将与它对称的点都标记可以移到原点即可
#include <bits/stdc++.h>
using namespace std;
const int N(1000100);
int n,m,a[N],ed[N],ans[N];
bool vis[N];
int e[N],h[N],ne[N],idx;
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void dfs(int u){
for(int i=h[u];~i;i=ne[i]){
int v=e[i];
ans[v]=-ans[u],ed[v]=ed[u];
dfs(v);
}
}
void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
int main(){
memset(h,-1,sizeof(h));
n=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read();
int l=1,r=1e6,pos=0;
for(int i=1;i<=m;i++){
int d=read();
if(l>pos) pos+=d;
else pos-=d;
//l,r,pos的相对位置不影响
if(pos<l||pos>r) continue;//l,r不会被割开
if(pos-l<r-pos){
//从多的部分指向少的部分,只保存多的部分继续往下做,少的部分通过对称得出
for(int i=l;i<pos;i++) add(2*pos-i,i),vis[i]=1;/*i不可以做开始点*/
l=pos+1,ed[pos]=i;
}
else{
for(int i=pos+1;i<=r;i++) add(2*pos-i,i),vis[i]=1;
r=pos-1,ed[pos]=i;
}
}
for(int i=l;i<=r;i++) ans[i]=i-pos;
for(int i=1;i<=1e6;i++) if(!vis[i]) dfs(i);
for(int i=1;i<=n;i++)
if(ed[a[i]]) printf("Yes %d\n",ed[a[i]]);
else printf("No %d\n",ans[a[i]]);
return 0;
}