N 個營地(N ≤ 50,000),初始人數給定。M ≤ 40,000 操作:
Add i j:第 i 營地增加 j 人Sub i j:第 i 營地減少 j 人Query i j:查詢區間 [i, j] 總人數End:結束當前測試用例sumO(N),遞歸構建左右子樹O(log N):遞歸找到葉子修改,回溯更新祖先O(log N):區間完全包含直接返回,否則拆分左右子區間#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 50005;
int a[MAXN];
struct Node { int l, r, sum; } tree[MAXN << 2];
void build(int l, int r, int idx) {
tree[idx].l = l; tree[idx].r = r;
if (l == r) { tree[idx].sum = a[l]; return; }
int mid = (l + r) >> 1;
build(l, mid, idx<<1);
build(mid+1, r, idx<<1|1);
tree[idx].sum = tree[idx<<1].sum + tree[idx<<1|1].sum;
}
void update(int idx, int pos, int val) {
if (tree[idx].l == tree[idx].r) {
tree[idx].sum += val; return;
}
int mid = (tree[idx].l + tree[idx].r) >> 1;
if (pos <= mid) update(idx<<1, pos, val);
else update(idx<<1|1, pos, val);
tree[idx].sum = tree[idx<<1].sum + tree[idx<<1|1].sum;
}
int query(int idx, int L, int R) {
if (tree[idx].l == L && tree[idx].r == R) return tree[idx].sum;
int mid = (tree[idx].l + tree[idx].r) >> 1;
if (R <= mid) return query(idx<<1, L, R);
if (L > mid) return query(idx<<1|1, L, R);
return query(idx<<1, L, mid) + query(idx<<1|1, mid+1, R);
}
int main() {
int T; scanf("%d", &T);
for (int cas = 1; cas <= T; cas++) {
int N; scanf("%d", &N);
for (int i = 1; i <= N; i++) scanf("%d", &a[i]);
build(1, N, 1);
printf("Case %d:\n", cas);
char cmd[10];
while (scanf("%s", cmd)) {
if (cmd[0] == 'E') break;
int x, y; scanf("%d%d", &x, &y);
if (cmd[0] == 'Q') printf("%d\n", query(1, x, y));
else if (cmd[0] == 'A') update(1, x, y);
else update(1, x, -y); // Sub
}
}
return 0;
}
O(N)O(log N)O((N + M) log N),完全滿足限制O(N)Add/Sub 只是單點加減,非區間操作scanf/printf