题目地址:
https://www.luogu.com.cn/problem/P2068
题目描述:
给定一个长度为
n
(
n
≤
100000
)
n(n\leq 100000)
n(n≤100000),初始值都为
0
0
0的序列,
x
(
x
≤
100000
)
x(x\leq 100000)
x(x≤100000)次的修改某些位置上的数字,每次加上一个数,然后提出
y
(
y
≤
100000
)
y(y\leq 100000)
y(y≤100000)个问题,求每段区间的和。
输入格式:
第一行
1
1
1个整数,表示序列的长度
n
n
n。
第二行
1
1
1个整数,表示操作的次数
w
w
w。
后面依次是
w
w
w行,分别表示加入和询问操作。
其中,加入用x
表示,询问用y
表示。
x
x
x的格式为x a b
表示在序列上第
a
a
a个数加上
b
b
b。保证
1
≤
a
≤
n
1 \leq a \leq n
1≤a≤n,
1
≤
b
≤
1
0
9
1 \leq b \leq 10^9
1≤b≤109。
y
y
y的格式为y a b
表示询问
a
a
a到
b
b
b区间的加和。保证
1
≤
a
≤
b
≤
n
1 \leq a \leq b \leq n
1≤a≤b≤n。
输出格式:
每行一个正整数,分别是每次询问的结果。
可以用线段树。代码如下:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m;
struct Node {
int l, r;
long sum;
} tr[N << 2];
void pushup(int u) {
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void build(int u, int l, int r) {
tr[u] = {l, r, 0};
if (l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
void add(int u, int k, long x) {
if (k <= tr[u].l && tr[u].r <= k) {
tr[u].sum += x;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (k <= mid) add(u << 1, k, x);
else add(u << 1 | 1, k, x);
pushup(u);
}
long query(int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
int mid = tr[u].l + tr[u].r >> 1;
long res = 0;
if (l <= mid) res += query(u << 1, l, r);
if (r > mid) res += query(u << 1 | 1, l, r);
return res;
}
int main() {
scanf("%d%d", &n, &m);
build(1, 1, n);
while (m--) {
char ch;
cin >> ch;
if (ch == 'x') {
int k, x;
scanf("%d%d", &k, &x);
add(1, k, x);
} else {
int l, r;
scanf("%d%d", &l, &r);
printf("%ld\n", query(1, l, r));
}
}
}
每次操作时间复杂度 O ( log n ) O(\log n) O(logn),空间 O ( n ) O(n) O(n)。