『题解』Luogu P8891 「UOI-R1」询问
题目大意
给定 \(n\) 个数 \(a_1,a_2,\dots,a_n\),有 \(m\) 次操作,每次给定 \(x,y\),需要找到所有的 \(i\) 满足 \(i \oplus x=0\),使 \(a_i \gets a_i-y\)。如果没有这样的 \(i\),就什么也不用做。
求完成所有操作后的序列。
\(1 \le n,m \le 10^6,-10^8 \le y,a_i \le 10^8,0 \le x \le n\).
思路
签到题。
我们知道 \(\oplus\) 的性质是,当 \(a=b\) 时,\(a \oplus b=0\),其他情况 \(a \oplus b \ne0\)。
这道题有了这个性质就很好做了,题目中的 \(i \oplus x=0\) 就是 \(i=x\) 的意思,于是我们只需要 \(a_x \gets a_x-y\) 即可。
还需要注意一下 \(0 \le x \le n\),当 \(x=0\) 时,不进行操作。
此题还要开 long long
,考虑极端数据,对一个数进行 \(10^6\) 次 \(x \gets x+10^8\) 的情况,那么 \(x\) 可达 \(10^{14}\),int
会爆掉。
代码
#include <iostream>
using namespace std;
template<typename T=int>
inline T read(){
T X=0; bool flag=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') flag=0; ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<1)+(X<<3)+(ch^48),ch=getchar();
if(flag) return X;
return ~(X-1);
}
const int N=1e6+5;
typedef long long ll;
int n,m,x,y;
ll a[N];
int main(){
n=read(),m=read();
for(int i=1; i<=n; i++) a[i]=read();
while(m--){
x=read(),y=read();
if(x==0) continue;
a[x]-=y;
}
for(int i=1; i<=n; i++) printf("%lld ",a[i]);
puts("");
return 0;
}