Coderforces 242E XOR on Segment

题意:给定一个序列,要求完成俩个操作

1)查询区间[l,r] 的和

2)区间更新, 区间每一个数都异或一个数x

对每一个查询输出结果

分析:对区间更新和查询这种操作,比较明显的就想到了线段树。区间查询比较简单,关键是区间更新该如何解决。

我们为线段数的每一个节点开一个cnt[20] 的数组,保存该区间内每一个数二进制位上1的个数,cnt[0] 表示对应区间内所有数第一个二进制数上1的个数和,这样,针对每一个异或操作,我们可以这样解决:

		for(int i = 0; i < L; ++i)
		{
			if(!(v & ( 1 << i) )) continue;//针对异或操作的性质,如果v的第i位为0,则这个区间内,第i位上的1的个数不变;
                                //若第i位为1,则第i为上1 的个数和0 的个数互换 p[k].cnt[i] = p[k].r-p[k].l + 1 - p[k].cnt[i]; }

这样,在计算区间和时

		for(int i = 0; i < L; ++i)
			ans += ((p[k].cnt[i] * 1ll) << i);

当然,要加速对区间更新的操作,肯定要运用lazy的思想

完整代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 100000 + 10;
const int L = 20; 

struct Node
{
    int l,r;
    int c,cnt[L];//cnt[i] 表示区间[l,r]内二进制第i位上1的个数
}p[3*N];
int que[N];
 
void build(int k,int s,int t)
{
    int kl, kr, mid;
    p[k].l = s; p[k].r = t;p[k].c = 0;
    if(s == t) {
        for(int i = 0; i < L; ++i)
        {
            if(que[s] & ( 1 << i ))  
                p[k].cnt[i] = 1;
        }
        return ;
    }
    mid=(s + t) >> 1; kl = k << 1; kr = kl + 1;
    build(kl, s, mid);
    build(kr, mid+1, t);
    for(int i = 0; i < L; ++i)
        p[k].cnt[i] = p[kl].cnt[i] + p[kr].cnt[i];
}

void Push_Down(int k, int v)
{
        p[k].c ^= v;
        for(int i = 0; i < L; ++i)
        {
            if(!(v & ( 1 << i) )) continue;
            p[k].cnt[i] = p[k].r-p[k].l + 1 - p[k].cnt[i];
        }
}
 
void insert(int k,int s,int t,int v)
{
    if(s <= p[k].l&& t >= p[k].r)
    {
        Push_Down(k, v);
        return ;
    }
    else {

        int mid=(p[k].r + p[k].l) >> 1, kl = k << 1, kr = kl + 1;
        if(p[k].c != 0)
        {
            Push_Down(kl, p[k].c);
            Push_Down(kr, p[k].c);
            p[k].c = 0;
        }
        if(s <= mid) insert(kl, s, t, v);
        if(t > mid) insert(kr, s, t, v);
        for(int i = 0; i < L; ++i)
            p[k].cnt[i] = p[kr].cnt[i] + p[kl].cnt[i];
    }
}
 
__int64 query(int k,int s,int t)
{
    if(s <= p[k].l && t >= p[k].r)
    {
        __int64 ans = 0;
        for(int i = 0; i < L; ++i)
            ans += ((p[k].cnt[i] * 1ll) << i);
        return ans;
    }

    int mid=(p[k].r + p[k].l) >> 1,kl = k << 1,kr = kl + 1;

    if(p[k].c)
    {
        Push_Down(kl, p[k].c);
        Push_Down(kr, p[k].c);
        p[k].c = 0;
    }
    __int64 a = 0,b = 0;
    if(s <= mid) a = query(kl,s,t);
    if(t > mid) b = query(kr,s,t);
    for(int i = 0; i < L; ++i)
        p[k].cnt[i] = p[kl].cnt[i] + p[kr].cnt[i];
    return a + b;
}
 
int main()
{
    int i,n,m,a,b,t,k;
    scanf("%d",&n);
        for(i = 1; i <= n; ++i) scanf("%d",que + i);
        build(1,1,n);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d",&k);
            if(k == 1)
            {
               scanf("%d %d",&a,&b);
               printf("%I64d\n",query(1,a,b));
            }
            else
            {
               scanf("%d %d %d",&a,&b,&t);
               if(t != 0)
                   insert(1,a,b,t);
            }
        }
    return 0;
}
原文地址:https://www.cnblogs.com/nanke/p/2952610.html