『题解』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;
}
posted @ 2022-12-11 15:49  仙山有茗  阅读(48)  评论(0编辑  收藏  举报