codeforces 242E - XOR on Segment

這種形式的題還是不熟悉。

對於十進制數的異或運算不滿足分配率,因而無法直接記錄區間和。

記錄[l, r]區間各個二進制位上1的數目,而各個二進制位上1的數目小於或等於r - l + 1(由於ai<10000000 < 1<<20 = 1048576,可以記錄20個位就行了);

異或運算滿足結合率,因而可延遲標記要異或的數。

最後把二進制轉換成十進制就行了,會暴int。


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <map>
#include <iostream>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
const int maxn = 100010;
struct Tree
{
    int dig[22];
}tree[maxn<<2];
int lazy[maxn<<2];
void PushUp(int rt)
{
    for(int i= 0; i < 22; i++)
    {
        tree[rt].dig[i] = tree[rt<<1].dig[i] + tree[rt << 1|1].dig[i];
    }
}
void PushDown(int rt, int l, int r)
{
    if(lazy[rt] == 0) return;
    lazy[rt<<1] ^= lazy[rt];
    lazy[rt<<1|1] ^= lazy[rt];
    int m = (l + r) >> 1;
    for(int i = 0; i < 22; i++)
    {
        int d = 1 << i;
        if(lazy[rt] & d)
        {
            tree[rt << 1].dig[i] = m - l + 1 - tree[rt << 1].dig[i];
            tree[rt << 1|1].dig[i] = r - m - tree[rt << 1|1].dig[i];
        }
    }
    lazy[rt] = 0;
}
void Build(int l, int r, int rt)
{
    lazy[rt] = 0;
    if(l == r)
    {
        int a;
        cin >> a;
        for(int i = 0; i < 22; i++)
        {
            if(a & 1 << i)
                tree[rt].dig[i] = 1;
            else 
                tree[rt].dig[i] = 0;
        }
        return;
    }
    int m = (l + r) >> 1;
    Build(lson);
    Build(rson);
    PushUp(rt);
}

void Update(int l, int r, int rt, int L, int R, int x)
{
    if(L <= l && r <= R)
    {
        lazy[rt] ^= x;
        for(int i = 0; i < 22; i++)
        {
            if(x & (1 << i))
            {
                tree[rt].dig[i] = r - l + 1 - tree[rt].dig[i];
            }
        }
        return ;
    }
    PushDown(rt, l, r);
    int m = (l + r) >> 1;
    if(L <= m)
        Update(lson, L, R, x);
    if(m < R)
        Update(rson, L, R, x);
    PushUp(rt);
}
long long  Query(int l, int r, int rt, int L, int R)
{
    long long ret = 0;
    if(L <= l && r <= R)
    {
        for(int i = 0; i < 22; i++)
        {
            ret = ret + (long long)tree[rt].dig[i] * (1 << i);
        }
        return ret;
    }
    PushDown(rt, l, r);
    int m = (l + r) >> 1;
    if(L <= m)
        ret += Query(lson, L, R);
    if(m < R)
        ret += Query(rson, L, R);
    PushUp(rt);
    return ret;
}
int main()
{
    int n;
    while(cin>>n)
    {
        Build(1, n, 1);
        int m;
        cin >> m;
        while(m--)
        {
            int cmd, l, r, x;
            cin >> cmd;
            if(cmd == 1)
            {
                cin >> l >> r;
                cout << Query(1, n, 1, l, r) << endl;
            }
            else
            {
                cin >> l >> r >> x;
                Update(1, n, 1, l, r, x);
            }
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章