NC19429 红球进黑洞

题目链接

题目

题目描述

在心理疏导室中有一种奇特的疏导工具,叫做红球。红球被提前分为了许多正方形小方格。
每当有人来找ATB做心理疏导时,ATB就会让他去先玩红球,然后通过红球小格方的高度来判断一个人的压力程度的高低。
具体地讲,ATB会让该人对于一个序列执行以下操作

  1. 区间求和,即输入 \(l,r\) ,输出 \(\sum_{i=l}^{r} x_i\)
  2. 区间异或,即输入 \(l,r,k\) ,对于\(l ≤ i ≤ r\) ,将 \(x_i\) 变为 \(x_i \oplus k\)
    可是ATB天天算计那么多答案,已经对这份工作产生了厌烦,所以请你帮帮他,对于一组给定的数据,输出对应的答案
    ATB会将你感谢到爆

输入描述

第一行两个整数 \(n\)\(m\) ,表示数列长度和询问次数
第二行有 \(n\) 个整数,表示这个数列的初始数值
接下来有 \(m\) 行,形如 1 l r 或者 2 l r k
分别表示查询 \(\sum_{i=l}^{r} a_i\)
或者对于 \(l ≤ i ≤ r\) ,将 \(x_i\) 变为 \(x_i \oplus k\)

输出描述

对于每一个查询操作,输出查询的结果并换行

示例1

输入

10 10
8 5 8 9 3 9 8 3 3 6 
2 1 4 1
1 2 6 
2 9 10 8
1 1 7 
2 4 7 8
2 8 8 6
2 2 3 0
1 1 2 
2 9 10 4
1 2 3 

输出

33
50
13
13

备注

  1. 数据范围
    对于 \(30\%\) 的数据,保证 \(n, m, k≤ 10\)
    对于另外 \(30\%\) 的数据,保证 \(n, m ≤ 50000, k ∈ \{0, 1\}\)
    对于全部 \(100\%\) 的数据,保证 \(1 ≤ n,m ≤ 10^5, 0≤ a_i,k ≤ 10^5\)

  2. 说明
    \(a \oplus b\) 表示 \(a \text{ xor } b\)

题解

知识点:线段树,位运算。

显然我们无法对区间和作异或运算,这导致区间修改无法懒标记。

但是,我们可以尝试按位考虑,记录一个区间每一位的 \(1\) 有多少个,这样做也是可以复原区间和的。同时,区间异或就转化成每位 \(0,1\) 数量置换,这是可以使用懒标记的信息。

随后就是朴素的线段树区间查询、区间修改。

时间复杂度 \(O((n+m)) \log n\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct T {
    int len;
    ll sum;
    array<int, 31> bits;
    static T e() { return { 0,0,{} }; }
    friend T operator+(const T &a, const T &b) {
        T x = T::e();
        x.len = a.len + b.len;
        x.sum = a.sum + b.sum;
        for (int i = 0;i <= 30;i++) x.bits[i] = a.bits[i] + b.bits[i];
        return x;
    }
};
struct F {
    int oplus;
    static F e() { return { 0 }; }
    T operator()(const T &x) {
        T fx = T::e();
        fx.len = x.len;
        for (int i = 0;i <= 30;i++) fx.bits[i] = oplus >> i & 1 ? x.len - x.bits[i] : x.bits[i];
        for (int i = 0;i <= 30;i++) fx.sum += fx.bits[i] * (1LL << i);
        return fx;
    }
    F operator()(const F &f) { return { f.oplus ^ oplus }; }
};

template <class T, class F>
class SegmentTreeLazy {
    int n;
    vector<T> node;
    vector<F> lazy;

    void push_down(int rt) {
        node[rt << 1] = lazy[rt](node[rt << 1]);
        lazy[rt << 1] = lazy[rt](lazy[rt << 1]);
        node[rt << 1 | 1] = lazy[rt](node[rt << 1 | 1]);
        lazy[rt << 1 | 1] = lazy[rt](lazy[rt << 1 | 1]);
        lazy[rt] = F::e();
    }

    void update(int rt, int l, int r, int x, int y, F f) {
        if (r < x || y < l) return;
        if (x <= l && r <= y) return node[rt] = f(node[rt]), lazy[rt] = f(lazy[rt]), void();
        push_down(rt);
        int mid = l + r >> 1;
        update(rt << 1, l, mid, x, y, f);
        update(rt << 1 | 1, mid + 1, r, x, y, f);
        node[rt] = node[rt << 1] + node[rt << 1 | 1];
    }

    T query(int rt, int l, int r, int x, int y) {
        if (r < x || y < l) return T::e();
        if (x <= l && r <= y) return node[rt];
        push_down(rt);
        int mid = l + r >> 1;
        return query(rt << 1, l, mid, x, y) + query(rt << 1 | 1, mid + 1, r, x, y);
    }

public:
    SegmentTreeLazy(int _n = 0) { init(_n); }
    SegmentTreeLazy(const vector<T> &src) { init(src); }

    void init(int _n) {
        n = _n;
        node.assign(n << 2, T::e());
        lazy.assign(n << 2, F::e());
    }
    void init(const vector<T> &src) {
        assert(src.size() >= 2);
        init(src.size() - 1);
        function<void(int, int, int)> build = [&](int rt, int l, int r) {
            if (l == r) return node[rt] = src[l], void();
            int mid = l + r >> 1;
            build(rt << 1, l, mid);
            build(rt << 1 | 1, mid + 1, r);
            node[rt] = node[rt << 1] + node[rt << 1 | 1];
        };
        build(1, 1, n);
    }

    void update(int x, int y, F f) { update(1, 1, n, x, y, f); }

    T query(int x, int y) { return query(1, 1, n, x, y); }
};

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, m;
    cin >> n >> m;
    vector<T> a(n + 1);
    for (int i = 1;i <= n;i++) {
        int x;
        cin >> x;
        a[i] = T::e();
        a[i].len = 1;
        a[i].sum = x;
        for (int j = 0;j <= 30;j++) a[i].bits[j] = x >> j & 1;
    }

    SegmentTreeLazy<T, F> sgt(a);
    while (m--) {
        int op, l, r;
        cin >> op >> l >> r;
        if (op == 1) cout << sgt.query(l, r).sum << '\n';
        else {
            int x;
            cin >> x;
            sgt.update(l, r, { x });
        }
    }
    return 0;
}
posted @ 2023-05-03 00:09  空白菌  阅读(13)  评论(0编辑  收藏  举报