QUERIES
#
给定一个长度为 n 的序列 , 每个数大小不超过 1000;
有 m 次操作,每次操作改变一个数的值,或求一段区间 [l, r] 的所有子区间的异或和之和。
多组数据。 每个操作第一个数是 opt
- 当 opt 为 1 时,读入 pos, val,表示修改第 pos 个数的值为 val。
- 当 opt 为 2 时,读入 l, r, 表示询问
#
#
线段树分治入门题。因为直接做看起来没什么思路,数的范围又在 1000 以内,考虑拆位算贡献。
表示序列上数的第 i 位所构建的线段树。
对于线段树上每个点:
-
定义 sum 为区间异或和。
-
l0、l1 表示区间内 从左到右连续的、异或和分别为 0、1 的子序列 个数。
r0、r1 表示区间内 从右到左连续的、异或和分别为 0、1 的子序列 个数。
-
s0、s1 表示区间内 异或和分别为 0、1 的子序列 个数。
转移也十分显然:
根据异或运算的规律 相同则 0, 不同为 1,可以很好理解上述转移式。
#
-
空间比较紧,注意到 ,所以线段树理论开 9 棵即可。
-
注意模数为 4001
-
也许可以定义一个类,这样构造、修改、查询都方便。
#
#include <bits/stdc++.h>
#define Rep(i, a, b) for (int i = (a), bb = (b); i <= bb; ++i)
const int N = 1e5 + 5, mod = 4001;
using namespace std;
int n, m, a[N], t, ans;
char BB[1 << 15], *S = BB, *T = BB;
#define getchar() (S == T && (T = (S = BB) + fread(BB, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
inline int read() {
int s = 0; char c = getchar(); for (; !isdigit(c); c = getchar());
for (; isdigit(c); c = getchar()) s = (s << 3) + (s << 1) + c - 48; return s;
}
template <class K> inline void write(K x) {
(x > 9 ? write(x / 10) : void());
return putchar(x % 10 + 48), void();
}
inline int add(int a, int b) { return a + b >= mod ? a + b - mod : a + b; }
inline void Add(int &a, int b) { return a = add(a, b), void(); }
inline int mul(int a, int b) { return 1LL * a * b % mod; }
inline void Mul(int &a, int b) { return a = mul(a, b), void(); }
struct Se_P {
int sum, s[2], l[2], r[2];
inline void clear(){sum = 0; Rep(i, 0, 1) s[i] = l[i] = r[i] = 0;}
} Void;
struct Segmentree {
Se_P t[N << 2], s; int tmp;
#define sum(p) t[p].sum
#define ls (p << 1)
#define rs (ls | 1)
#define mid ((x + y) >> 1)
#define Ls ls, x, mid
#define Rs rs, mid + 1, y
inline Se_P Spread(Se_P l, Se_P r) { s.clear();
s.s[0] = add(add(add(l.s[0], r.s[0]), mul(l.r[0], r.l[0])), mul(l.r[1], r.l[1]));
s.s[1] = add(add(add(l.s[1], r.s[1]), mul(l.r[0], r.l[1])), mul(l.r[1], r.l[0]));
if (l.sum == 0) s.l[0] = l.l[0] + r.l[0], s.l[1] = l.l[1] + r.l[1];
else s.l[0] = l.l[0] + r.l[1], s.l[1] = l.l[1] + r.l[0];
if (r.sum == 0) s.r[0] = r.r[0] + l.r[0], s.r[1] = r.r[1] + l.r[1];
else s.r[0] = r.r[0] + l.r[1], s.r[1] = r.r[1] + l.r[0];
s.sum = l.sum ^ r.sum;
return s;
}
inline void Push(int p) { return t[p] = Spread(t[ls], t[rs]), void(); }
inline void Build(int p, int x, int y, int op) {
t[p].clear();
if (x == y) {
tmp = (a[x] & (1 << op)) ? 1 : 0;
return t[p].l[tmp] = t[p].r[tmp] = t[p].s[tmp] = 1, sum(p) = tmp, void();
}
return Build(Ls, op), Build(Rs, op), Push(p);
}
inline void Modify(int p, int x, int y, int pos, int v) {
if (x == y) return t[p].clear(), t[p].l[v] = t[p].r[v] = t[p].s[v] = 1, sum(p) = v, void();
(pos <= mid ? Modify(Ls, pos, v) : Modify(Rs, pos, v)), Push(p);
}
inline Se_P Ask(int p, int x, int y, int l, int r) {
if (l > r || x > y || x > r || l > y) return Void;
if (l <= x && y <= r) return t[p];
return Spread(Ask(Ls, l, r), Ask(Rs, l, r));
}
} Se[10];
int main(void) {
n = read(), m = read(), Void.clear();
Rep(i, 1, n) a[i] = read();
Rep(i, 0, 9) Se[i].Build(1, 1, n, i);
Rep(i, 1, m) {
int opt = read(), x = read(), y = read();
if (opt == 1) {
Rep(i, 0, 9) Se[i].Modify(1, 1, n, x, (y & (1 << i)) ? 1 : 0);
}
if (opt == 2) {
t = 1, ans = 0;
Rep(i, 0, 9) Add(ans, mul(Se[i].Ask(1, 1, n, x, y).s[1], t)), Mul(t, 2);
write(ans), putchar(10);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律