思路简述
比较明显的分块题,考虑用一个 b 数组存储 a 数组中每一个元素,分块之后再在 b 数组上对每一个块内元素进行排序。排完序后,对每一个块做一个前缀和,便于求和。对于每一次查询,对于覆盖了一整块的区间询问,可以用在 b 数组上二分查找的方式找出区间内小于等于 x 的元素之和;而对于没有覆盖一整个块的区间询问,直接暴力统计即可。
唯一要注意的事情:块长不能开为 n \sqrt n n,会被卡掉;建议使用 2000 2000 2000 左右的块长。
代码
#include <bits/stdc++.h>
#define _FOR(i, a, b) for (int(i) = (a); (i) <= (b); ++(i))
typedef long long i64;
const int N = 2e5 + 5;
int n, pos[N], st[1005], ed[1005], Q;
i64 alpha, beta, garma, B, a[N], b[N], sum[N];
inline i64 Query(int l, int r, i64 val) {
int p = pos[l], q = pos[r];
i64 res = 0;
if (p == q) {
_FOR(i, l, r) {
if (a[i] <= val) res += a[i];
}
return res;
}
_FOR(i, l, ed[p]) {
if (a[i] <= val) res += a[i];
}
_FOR(i, st[q], r) {
if (a[i] <= val) res += a[i];
}
_FOR(i, p + 1, q - 1) {
if (b[st[i]] > val) continue;
int L = st[i], R = ed[i];
while (L < R) {
int Mid = (L + R + 1) >> 1;
if (b[Mid] <= val) L = Mid;
else R = Mid - 1;
}
res += sum[L];
}
return res;
}
int main() {
std::cin >> n;
int block = 2000;
int t = n / block + (n % block ? 1 : 0);
_FOR(i, 1, n) {
std::cin >> a[i];
b[i] = a[i];
pos[i] = (i - 1) / block + 1;
}
_FOR(i, 1, t) {
st[i] = (i - 1) * block + 1;
ed[i] = i * block;
}
ed[t] = n;
_FOR(i, 1, t) {
std::sort(b + st[i], b + ed[i] + 1);
sum[st[i]] = b[st[i]];
_FOR(j, st[i] + 1, ed[i]) {
sum[j] = sum[j - 1] + b[j];
}
}
std::cin >> Q;
while (Q--) {
std::cin >> alpha >> beta >> garma;
i64 L = alpha ^ B, R = beta ^ B, X = garma ^ B;
B = Query(L, R, X);
std::cout << B << '\n';
}
return 0;
}