NC19429 红球进黑洞
题目
题目描述
在心理疏导室中有一种奇特的疏导工具,叫做红球。红球被提前分为了许多正方形小方格。
每当有人来找ATB做心理疏导时,ATB就会让他去先玩红球,然后通过红球小格方的高度来判断一个人的压力程度的高低。
具体地讲,ATB会让该人对于一个序列执行以下操作
- 区间求和,即输入 ,输出
- 区间异或,即输入 ,对于 ,将 变为
可是ATB天天算计那么多答案,已经对这份工作产生了厌烦,所以请你帮帮他,对于一组给定的数据,输出对应的答案
ATB会将你感谢到爆
输入描述
第一行两个整数 和 ,表示数列长度和询问次数
第二行有 个整数,表示这个数列的初始数值
接下来有 行,形如 1 l r 或者 2 l r 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
备注
-
数据范围
对于 的数据,保证
对于另外 的数据,保证
对于全部 的数据,保证 -
说明
表示
题解
知识点:线段树,位运算。
显然我们无法对区间和作异或运算,这导致区间修改无法懒标记。
但是,我们可以尝试按位考虑,记录一个区间每一位的 有多少个,这样做也是可以复原区间和的。同时,区间异或就转化成每位 数量置换,这是可以使用懒标记的信息。
随后就是朴素的线段树区间查询、区间修改。
时间复杂度
空间复杂度
代码
#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; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/17368545.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧