SMOJ 1980 XOR (线段树)

SMOJ 1980 XOR (线段树)_第1张图片
SMOJ 1980 XOR (线段树)_第2张图片
SMOJ 1980 XOR (线段树)_第3张图片


Solution

这就是棵裸的线段树,我一下就切掉了。话说最近考了好多好多道线duang树啊!感觉我自己都被duang掉了。

由于异或不满足分配律,不能像矩阵那题一样直接对和进行异或操作。而异或是满足结合律的,于是我们可以对于多个异或标记进行合并。

我们抓住异或的本质(别说抓不住),异或x就是如果x二进制的某一位是1,就将被异或的那个数的那一位1变成0,0变成1。我们就在线段树的叶子开一个大小为20左右的数组,记录二进制下每一位是0是1。然后向上维护每一位的和。我们知道一段区间的1个个数就是和,0的个数就是区间长度减去和。我们对这段区间异或x,将x分解,有一位是1,代表将这段区间的每一个数的1变0,0变1,再求和。其实和就变成了区间长度减去和了。于是和就可以进行区间信息加法了。

然后将懒惰标记lazy合并后向下传,和也照样维护,到底端就变成了那一位是0是1了。查询的时候再将对应的位的权乘和累加起来,然后这题就这样的过了。

时间的话,多一个20倍的常数,然而题目良心,操作不多,所以不虚。

ps:这题的数据有毒??我暴力跟正解拍了半天没出错,正解一交AC了,暴力却只有20分,WA了一堆,真是让我长见识了!另外有人的暴力拿了50分,一问,答曰:我的线段树的标记是down到底的,太强大了!我震惊得说不出话来,此处省略rand()+1字。


代码

#include 
#include 
#include 
#include 
#include 
#include 
#define maxn 100010

using namespace std;

typedef long long LL;
int n, m, a[maxn];

struct Tnode{
    int num[22];
    int lazy;
}tree[maxn<<2];

void build(int root, int L, int R){
    if(L == R){
        int temp = a[L], t = 0;
        while(temp){
            tree[root].num[t] = temp & 1;
            t ++;
            temp >>= 1;
        }
        tree[root].lazy = 0;
        return;
    }

    int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;
    build(Lson, L, mid);
    build(Rson, mid+1, R);

    for(int i = 0; i <= 20; i++)  
        tree[root].num[i] = tree[Lson].num[i] + tree[Rson].num[i];
    tree[root].lazy = 0;
}

void Down(int root, int L, int R){
    if(!tree[root].lazy)  return;
    int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;

    int temp = tree[root].lazy, t = 0;
    while(temp){
        if(temp & 1){
            tree[Lson].num[t] = (mid - L + 1) - tree[Lson].num[t];
            tree[Rson].num[t] = (R - mid) - tree[Rson].num[t];
        }
        t ++;
        temp >>= 1;
    }

    tree[Lson].lazy ^= tree[root].lazy;
    tree[Rson].lazy ^= tree[root].lazy;
    tree[root].lazy = 0;
}

void update(int root, int L, int R, int x, int y, int v){
    if(x > R || y < L)  return;
    if(x <= L && y >= R){
        int temp = v, t = 0;
        while(temp){
            if(temp & 1)  tree[root].num[t] = (R - L + 1) - tree[root].num[t];
            t ++;
            temp >>= 1;
        }
        tree[root].lazy ^= v;
        return;
    }

    Down(root, L, R);

    int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;

    update(Lson, L, mid, x, y, v);
    update(Rson, mid+1, R, x, y, v);

    for(int i = 0; i <= 20; i++)  
        tree[root].num[i] = tree[Lson].num[i] + tree[Rson].num[i];
}

LL query(int root, int L, int R, int x, int y){
    if(x > R || y < L)  return 0LL;
    if(x <= L && y >= R){
        LL ans = 0LL;
        for(int i = 0; i <= 20; i++)  ans += (1LL << i) * tree[root].num[i];
        return ans;
    }

    Down(root, L, R);

    int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;

    LL temp1 = query(Lson, L, mid, x, y);
    LL temp2 = query(Rson, mid+1, R, x, y);

    return temp1 + temp2;
}

int main(){

    scanf("%d", &n);

    for(int i = 1; i <= n; i++)  scanf("%d", &a[i]);

    build(1, 1, n);

    scanf("%d", &m);

    int t, l, r, x;
    for(int i = 1; i <= m; i++){
        scanf("%d%d%d", &t, &l, &r);
        if(t == 1)
            printf("%lld\n", query(1, 1, n, l, r));
        else{
            scanf("%d", &x);
            update(1, 1, n, l, r, x);
        }
    }

    return 0;
}

SMOJ 1980 XOR (线段树)_第4张图片

你可能感兴趣的:(非可持久化数据结构)