CF 242E XOR on Segment 【线段树】

89 篇文章 0 订阅
42 篇文章 0 订阅

两种操作:

1、求区间和

2、对区间上的每一个数进行异或(xor)运算

直接维护区间和的话区间更新无法进行,所以,要维护的信息是区间内按位和(即每个二进制位出现的次数),那么进行xor运算的时候,只需要进行0 和 1的转换就可以了。

这样的话,就是一个基本线段树+延迟操作+维护各个二进制位信息。



#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
#define N 100100

int c[N<<2][20], n, q, x[N<<2];

void Up(int rt) {
    for (int i=0; i<20; i++) c[rt][i] = c[rt<<1][i] + c[rt<<1|1][i];
}
void Down(int L, int R, int rt) {
    if (x[rt]) {
        int Mid = (L + R) >> 1;
        x[rt<<1] ^= x[rt];
        x[rt<<1|1] ^= x[rt];
        for (int i=0; i<20; i++) {
            if (!(x[rt] & (1<<i))) continue;
            c[rt<<1][i] = Mid-L+1 - c[rt<<1][i];
            c[rt<<1|1][i] = R-Mid - c[rt<<1|1][i];
        }
        x[rt] = 0;
    }
}
void build(int L, int R, int rt) {
    x[rt] = 0;
    if (L == R) {
        int t; scanf("%d", &t);
        for (int i=0; i<20; i++)
            if (t&(1<<i)) c[rt][i] = 1; else c[rt][i] = 0;
        return ;
    }
    int Mid = (L + R) >> 1;
    build(L, Mid, rt<<1);
    build(Mid+1, R, rt<<1|1);
    Up(rt);
}
void update(int l, int r, int a, int L, int R, int rt) {
    if (l <= L && R <= r) {
        x[rt] ^= a;
        for (int i=0; i<20; i++) {
            if (!(a & (1<<i))) continue;
            c[rt][i] = R-L+1 - c[rt][i];
        }
        return ;
    }
    int Mid = (L+R) >> 1;
    Down(L, R, rt);

    if (l <= Mid) update(l, r, a, L, Mid, rt<<1);
    if (Mid < r) update(l, r, a, Mid+1, R, rt<<1|1);
    Up(rt);
}
ll query(int l, int r, int L, int R, int rt) {
    if (l <= L && R <= r) {
        ll ret = 0;
        for (int i=0; i<20; i++) ret += ((ll)c[rt][i])<<i;
        return ret;
    }

    int Mid = (L + R) >> 1;
    Down(L, R, rt);

    ll ret = 0;
    if (l <= Mid) ret += query(l, r, L, Mid, rt<<1);
    if (Mid < r) ret += query(l, r, Mid+1, R, rt<<1|1);
    Up(rt);
    return ret;
}
int main() {
    scanf("%d", &n);
    build(1, n, 1);

    scanf("%d", &q);
    int t, l, r, a;
    while (q--) {
        scanf("%d", &t);
        if (t == 1) {
            scanf("%d%d", &l, &r);
            printf("%I64d\n", query(l, r, 1, n, 1));
        } else {
            scanf("%d%d%d", &l, &r, &a);
            update(l, r, a, 1, n, 1);
        }
    }
    return 0;
}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值