Codeforces 242 E. XOR on Segment

传送门:>Here<

给出一个长度为\(n\)的序列\(a\)\(m\)次询问:一,询问区间和;二,区间异或上一个数\(x\)。(\(n,m \leq 10^5\)\(a_i,x \leq 10^6\)

解题思路

这是一个用线段树来维护区间位运算的问题。

首先将\(a_i\)全都看成二进制。二进制求和还有一种思路:不进位的二进制加法,即累积二进制的每一位上1的个数。线段树上每一个节点保存\(\log a_i\)个值,表示区间内某一位上1的个数和。这样就可以做区间位运算了。这道题中是异或,那么已知区间长度为\(r-l+1\),对于需要异或1的那一位,\(cnt_i \rightarrow (r-l+1)-cnt_i\)

\(Code\)

我一般采用的\(pushdown\)是先将当前节点的值更新并打上懒标。因此懒标只对它一下的点起作用。

/*DennyQi 2019*/
#include 
#include 
#include 
#include 
#define int long long
using namespace std;
const int N = 100010;
const int P = 998244353;
const int INF = 0x3f3f3f3f;
inline int mul(const int& a, const int& b){ return 1ll*a*b%P; }
inline int add(const int& a, const int& b){ return (a+b>=P)?a+b-P:a+b; }
inline int sub(const int& a, const int& b){ return (a-b<0)?a-b+P:a-b; }
inline int read(){
    int x(0),w(1); char c = getchar();
    while(c^'-' && (c<'0' || c>'9')) c = getchar();
    if(c=='-') w = -1, c = getchar();
    while(c>='0' && c<='9') x = (x<<3)+(x<<1)+c-'0', c = getchar(); 
    return x*w;
}
int n,m,opt,x,y,z,a[N],v[N<<2][21],tag[N<<2];
inline void pushup(int u){
    for(int i = 0; i <= 20; ++i){
        v[u][i] = v[u<<1][i] + v[u<<1|1][i];
    }
}
void build(int u, int l, int r){
    if(l == r){
        int j = 0;
        while(a[l] > 0){
            v[u][j] = (a[l] & 1);
            ++j;
            a[l] >>= 1;
        }
        return;
    }
    int mid = (l+r)>>1;
    build(u<<1,l,mid);
    build(u<<1|1,mid+1,r);
    pushup(u);
}
inline void xor_(int u, int l, int r, int k){
    for(int i = 0; i <= 20; ++i){
        int b = (k & 1);
        k >>= 1;
        if(b){
            v[u][i] = (r-l+1) - v[u][i];
        }
    }
}
inline void pushdown(int u, int l, int r){
    if(!tag[u]) return;
    int mid = (l+r)>>1;
    xor_(u<<1,l,mid,tag[u]);
    xor_(u<<1|1,mid+1,r,tag[u]);
    tag[u<<1] ^= tag[u];
    tag[u<<1|1] ^= tag[u];
    tag[u] = 0;
}
int query(int u, int l, int r, int x, int y){
    if(l > y || r < x) return 0;
    if(x <= l && r <= y){
        int res = 0;
        for(int i = 0; i <= 20; ++i){
            res += (1<>1;
    return query(u<<1,l,mid,x,y) + query(u<<1|1,mid+1,r,x,y);
}
void modify(int u, int l, int r, int x, int y, int k){
    if(l > y || r < x) return;
    if(x <= l && r <= y){
        tag[u] ^= k;
        xor_(u,l,r,k);
        return;
    }
    pushdown(u,l,r);
    int mid = (l+r)>>1;
    modify(u<<1,l,mid,x,y,k);  
    modify(u<<1|1,mid+1,r,x,y,k);
    pushup(u);
}
signed main(){
    // freopen("file.in","r",stdin);
    n = read();
    for(int i = 1; i <= n; ++i){
        a[i] = read();
    }
    build(1,1,n);
    m = read();
    while(m--){
        opt = read();
        if(opt == 1){
            x = read(), y = read();
            printf("%lld\n",query(1,1,n,x,y));
        }else{
            x = read(), y = read(), z = read();
            modify(1,1,n,x,y,z);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/qixingzhi/p/11255168.html

你可能感兴趣的:(Codeforces 242 E. XOR on Segment)