传送门

Solution

观察到 ai106<220a_i\le 10^6 <2^{20},拆位后数组变成 20 条长度为 nn01 串。开二十棵线段树分别维护这些串的区间和。

设一个串在区间 [l,r][l,r] 的和为 S,该区间与 11 异或后,新的和 S=rl+1SS'=r-l+1-S,即将区间内的 1100 互换。

Code

#include <bits/stdc++.h>
#define ls k<<1
#define rs k<<1|1
using namespace std;
typedef long long ll;

const ll N = 1e5 + 10, logN = 21;

ll n, a[N], L[N << 2], R[N << 2], Q, siz[N << 2];
struct Tree {
    ll sum, laz;
} T[N << 2][logN + 5];

void push_up(ll k) 
{
    for (int i = 0; i <= logN; i++)
        T[k][i].sum = T[ls][i].sum + T[rs][i].sum;
}

void push_down(ll k)
{
    for (int i = 0; i <= logN; i++) {
        if (!T[k][i].laz) continue; 
        T[ls][i].laz ^= T[k][i].laz;
        T[rs][i].laz ^= T[k][i].laz;
        T[ls][i].sum = siz[ls] - T[ls][i].sum;
        T[rs][i].sum = siz[rs] - T[rs][i].sum;
        T[k][i].laz = 0;
    }
}

void build(ll k, ll l, ll r)
{
    L[k] = l; R[k] = r; siz[k] = r - l + 1;
    if (l == r) {
        ll num = a[l];
        for (int i = 0; i <= logN; i++) {
            T[k][i].sum = (num & 1);
            num >>= 1;
        }
        return;
    }
    ll mid = (l + r) >> 1;
    build(ls, l, mid);
    build(rs, mid + 1, r);
    push_up(k);
}

void modify(ll k, ll x, ll y, ll z)
{
    if (x <= L[k] && R[k] <= y) {
        ll num = z;
        for (int i = 0; i <= logN; i++) {
            if (num & 1)
                T[k][i].sum = siz[k] - T[k][i].sum;
            T[k][i].laz ^= (num & 1);
            num >>= 1;
        }
        return;
    }
    ll mid = (L[k] + R[k]) >> 1;
    push_down(k);
    if (x <= mid) modify(ls, x, y, z);
    if (mid < y) modify(rs, x, y, z);
    push_up(k);
}

ll query(ll k, ll x, ll y) 
{
    ll res = 0;
    if (x <= L[k] && R[k] <= y) {
        for (int i = 0; i <= logN; i++)
            res += (1 << i) * T[k][i].sum;
        return res;
    }
    ll mid = (L[k] + R[k]) >> 1;
    push_down(k);
    if (x <= mid) res += query(ls, x, y);
    if (mid < y) res += query(rs, x, y);
    return res;
}

int main()
{
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    build(1, 1, n);
    scanf("%lld", &Q);
    while (Q--) {
        ll opt, x, y, z;
        scanf("%lld%lld%lld", &opt, &x, &y);
        if (opt == 1) {
            printf("%lld\n", query(1, x, y));
        } else {
            scanf("%lld", &z);
            modify(1, x, y, z);
        }
    }
    return 0;
}