码迷,mamicode.com
首页 > 其他好文 > 详细

关于区间异或的线段树

时间:2020-03-31 01:10:07      阅读:79      评论:0      收藏:0      [点我收藏+]

标签:c++   alt   fine   lse   code   关于   int   img   event   

题:https://codeforces.com/problemset/problem/242/E?csrf_token=e91633dfd98d038f51cc388731fe3f4d

题意:俩个操作,操作1:(l,r,x),区间[l,r]的数全部异或上x。操作2:(l ,r)输出区间[l,r]和;

分析:对数组a建线段树,对于线段树的每一个节点进行二进制拆位,每个位就统计有多少个1,更新操作对于涵盖区间的二进制位就等于其长度减去更新前的1的个数;

技术图片
#include<bits/stdc++.h>
using namespace std;
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
typedef long long ll;
const int N=30;
const int M=1e5+5;
ll lz[M<<2][N],tr[M<<2][N],a[M];
void up(int root){
    for(int i=0;i<=20;i++)
        tr[root][i]=tr[root<<1][i]+tr[root<<1|1][i];
}
void build(int root,int l,int r){
    if(l==r){
        int x=a[l];
        for(int i=0;i<=20;i++){
            if(x&(1<<i)){
                tr[root][i]=1;
            }
        }
        return ;
    }
    int midd=(l+r)>>1;
    build(lson);
    build(rson);
    up(root);
}
void pushdown(int root,int l,int r){
    for(int i=0;i<=20;i++){
        if(lz[root][i]){
           int midd=(l+r)>>1;
            tr[root<<1][i]=midd-l+1-tr[root<<1][i];
            tr[root<<1|1][i]=r-midd-tr[root<<1|1][i];
            lz[root<<1][i]^=lz[root][i];
            lz[root<<1|1][i]^=lz[root][i];
            lz[root][i]=0;
        }

    }
}
void update(int L,int R,int x,int root,int l,int r){
    if(L<=l&&r<=R){
        for(int i=0;i<=20;i++)
            if(x&(1<<i)){
                tr[root][i]=r-l+1-tr[root][i];///记录i位置二进制的个数
                lz[root][i]^=1;
            }
        return;

    }
    pushdown(root,l,r);
    int midd=(l+r)>>1;
    if(L<=midd)
        update(L,R,x,lson);
    if(R>midd)
        update(L,R,x,rson);
    up(root);
}
ll query(int L,int R,int root,int l,int r){
    if(L<=l&&r<=R){
        ll ans=0;
        for(int i=0;i<=20;i++){
            ans+=tr[root][i]*(1ll<<i);
        }
        return ans;
    }
    pushdown(root,l,r);
    int midd=(l+r)>>1;
    ll res=0;
    if(L<=midd)
        res=query(L,R,lson);
    if(R>midd)
        res+=query(L,R,rson);
    return res;
}
int main(){
    int n,m;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    build(1,1,n);
    scanf("%d",&m);
    while(m--){
        int op;
        scanf("%d",&op);
        if(op==1){
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%lld\n",query(l,r,1,1,n));
        }
        else{
            int l,r,x;
            scanf("%d%d%d",&l,&r,&x);
            update(l,r,x,1,1,n);
        }
    }
    return 0;
}
View Code

 

关于区间异或的线段树

标签:c++   alt   fine   lse   code   关于   int   img   event   

原文地址:https://www.cnblogs.com/starve/p/12602350.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!