线段树--codeforces242E XOR on Segment

给定1e5个数ai

操作1,求区间和

操作2,将ql,qr区间内所有数与x异或


线段树真神奇。。。。 将ai的每一位用线段树表示,20个线段树即可。

//又是1e5和线段树

//1.r - l + 1

//2.pushdownlc,rc要取反

//3.bitset<20>打成10

//4.seg,lazy线段树居然没有开<< 2

#include <iostream>

#include <cstdio>

#include <bitset>

using namespace std;


#define mid (l + r) / 2

#define lc (rt << 1)

#define rc (rt << 1 | 1)

const int maxn = 1e5 + 5;

typedef long long ll;


int seg[maxn << 2][20];//seg[x][q]表示第q棵树,为了和a的坐标对应

int lazy[maxn << 2][20];//区间修改

bitset<20> a[maxn];//0是低位

bitset<20>x;

int ql,qr;

ll weight[20];


int id;

void init(int l,int r,int rt)//query的时候再乘上2^i位权好了

{

    if(l == r){seg[rt][id] = a[l][id];return;}

    init(l, mid, lc);

    init(mid + 1, r, rc);

    seg[rt][id] = seg[lc][id] + seg[rc][id];

}

void pushdown(int l,int r,int rt)

{

    if(lazy[rt][id])

    {

        lazy[lc][id] ^= 1;//这里是取反

        lazy[rc][id] ^= 1;

        seg[lc][id] = (mid - l + 1) - seg[lc][id];

        seg[rc][id] = (r - mid) - seg[rc][id];

        lazy[rt][id] = 0;

    }

}

int query(int l,int r,int rt)//记录的是第id位上,1的个数

{

    if(ql <= l && r <= qr) {

       return seg[rt][id];

    }

    pushdown(l, r, rt);

    int ans = 0;

    if(ql <= mid) ans += query(l, mid, lc);

    if(mid < qr) ans += query(mid + 1, r, rc);

    return ans;

}


void update(int l,int r,int rt)

{

    if(ql <= l && r <= qr){

        lazy[rt][id] ^= 1;//取反

        seg[rt][id] = (r - l + 1) - seg[rt][id];//

        return;

    }

    pushdown(l,r,rt);

    if(ql <= mid) update(l, mid, lc);

    if(mid < qr) update(mid + 1, r, rc);

    seg[rt][id] = seg[lc][id] + seg[rc][id];

}


int main()

{

    int n,tmp;

    scanf("%d",&n);

    for (int i = 1; i <= n; i ++) {

        scanf("%d",&tmp);

        a[i] = tmp;

    }

    for (id = 0; id < 20; id ++) {

        init(1, n, 1);

        weight[id] = (1ll << id);

    }

    int m;scanf("%d",&m);

    int op;

    for (int i = 0; i < m; i ++) {//如果每个树里只存储01,而不计算位权,那么是不会超int,query int ok

        scanf("%d%d%d",&op,&ql,&qr);

        if(ql > qr) swap(ql, qr);

        if(op == 1){

            ll sum = 0;

            for (id = 0; id < 20; id ++) {

                sum += (ll)query(1, n, 1) * weight[id];

            }

            printf("%lld\n",sum);

        }

        else{

            scanf("%d",&tmp);

            x = tmp;

            for (id = 0; id < 20; id ++) {

                if(x[id])  update(1, n, 1);//只有该位为1时,才会改变

            }

        }

    }

    return 0;

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值