XOR(线段树)



题解:想要切这道题,你要知道以下几点:

1.异或具有结合律,即(a^b)^c=a^(b^c)

2.异或不具有分配律,即(a+b)^c≠a^c+b^c

知道了第二点,我们就不能简单的维护区间的和;知道了第一点,我们打标记以及push down就方便很多。

我们维护20棵线段树,假设第i棵线段树节点j对应区间为[l,r],该节点表示在原数列al-ar中,2^i出现的次数。然后对每个修改操作的数x用2进制表示出来,如果当前位是1,把区间中2^i的1和0的个数取反,然后注意一下push down的问题,Query和Insert的时候都要判断push down。(这个我曾经没down)

#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;

const int maxl=19;
int n,m,jin[20];
struct tedge
{
    int sum,t;
}tree[400010][20];
long long ans;

void Updata(int root,int l,int r,int wei,int x,int id)
{
    if (l==r&&r==wei)
    {
        tree[root][id].sum++;
        return;
    }
    int mid=(l+r)/2;
    if (wei<=mid) Updata(root*2,l,mid,wei,x,id);
    else Updata(root*2+1,mid+1,r,wei,x,id);
    tree[root][id].sum=tree[root*2][id].sum+tree[root*2+1][id].sum;
}

void Change(int root,int l,int r,int L,int R,int id)
{
    if (R<l||r<L) return;
    if (L<=l&&r<=R)
    {
        tree[root][id].sum=r-l+1-tree[root][id].sum;
        tree[root][id].t = 1-tree[root][id].t;
        return;
    }
    int mid=(l+r)/2;
    if (tree[root][id].t==1)
    {
        tree[root*2][id].sum=mid-l+1-tree[root*2][id].sum;
        tree[root*2+1][id].sum=r-(mid+1)+1-tree[root*2+1][id].sum;
        tree[root*2][id].t = 1-tree[root*2][id].t;
        tree[root*2+1][id].t = 1-tree[root*2+1][id].t;
        tree[root][id].t = 0;
    }
    Change(root*2,l,mid,L,R,id);  Change(root*2+1,mid+1,r,L,R,id);
    tree[root][id].sum=tree[root*2][id].sum+tree[root*2+1][id].sum;
}

long long Query(int root,int l,int r,int L,int R,int id)
{
    if (R<l||r<L) return 0;
    if (L<=l&&r<=R) return (long long)jin[id]*(long long)tree[root][id].sum;
    int mid=(l+r)/2;
    if (tree[root][id].t==1)
    {
        tree[root*2][id].sum=mid-l+1-tree[root*2][id].sum;
        tree[root*2+1][id].sum=r-(mid+1)+1-tree[root*2+1][id].sum;
        tree[root*2][id].t = 1-tree[root*2][id].t;
        tree[root*2+1][id].t = 1-tree[root*2+1][id].t;
        tree[root][id].t = 0;
    }
    
    return (long long)Query(root*2,l,mid,L,R,id)+(long long)Query(root*2+1,mid+1,r,L,R,id);
}

int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    scanf("%d",&n);
    jin[0] = 1;
    for (int i=1; i<=maxl; i++)
    jin[i] = jin[i-1]*2;
    for (int i=1; i<=n; i++)
    {
        int x;
        scanf("%d",&x);
        for (int j=0; j<=maxl; j++)
        {
            if (x%2==1) Updata(1,1,n,i,x%2,j);
            x = x/2;
        }
    }
    scanf("%d",&m);
    for (int i=1; i<=m; i++)
    {
        int id,l,r,x;  ans = 0;
        scanf("%d%d%d",&id,&l,&r);
        if (id==1)
        {
            for (int j=0; j<=maxl; j++)
            ans+=(long long)Query(1,1,n,l,r,j);
            printf("%lld\n",ans);
        }
        else
        {
            scanf("%d",&x);
            for (int j=0; j<=maxl; j++)
            {
                if (x%2==1) Change(1,1,n,l,r,j);
                x = x/2;
            }
        }
    }
    return 0;
}

 

posted @ 2017-09-27 19:47  最终惊吓者——Janous  阅读(446)  评论(0编辑  收藏  举报