题目地址:
https://www.acwing.com/problem/content/1269/
NK中学组织同学们去五云山寨参加社会实践活动,按惯例要乘坐火车去。由于NK中学的学生很多,在火车开之前必须清点好人数。初始时,火车上没有学生,当同学们开始上火车时,年级主任从第一节车厢出发走到最后一节车厢,每节车厢随时都有可能有同学上下。年级主任走到第 m m m节车厢时,他想知道前 m m m节车厢上一共有多少学生。他没有调头往回走的习惯,也就是说每次当他提问时, m m m总会比前一次大。
输入格式:
第一行两个整数
n
,
k
n,k
n,k,表示火车共有
n
n
n节车厢以及
k
k
k个事件。接下来有
k
k
k行,按时间先后给出
k
k
k个事件,每行开头都有一个字母
A
A
A,
B
B
B或
C
C
C。
如果字母为
A
A
A,接下来是一个数
m
m
m,表示年级主任现在在第
m
m
m节车厢;
如果字母为
B
B
B,接下来是两个数
m
,
p
m,p
m,p,表示在第
m
m
m节车厢有
p
p
p名学生上车;
如果字母为
C
C
C,接下来是两个数
m
,
p
m,p
m,p,表示在第
m
m
m节车厢有
p
p
p名学生下车。
学生总人数不会超过
1
0
5
10^5
105。
输出格式:
对于每个事件
A
A
A,输出一行,一个整数,表示年级主任的问题的答案。
数据范围:
1
≤
n
≤
5
×
1
0
5
1≤n≤5×10^5
1≤n≤5×105
1
≤
k
≤
1
0
5
1≤k≤10^5
1≤k≤105
即要求实现单点修改与查询前缀和,可以用树状数组来做。代码如下:
#include <iostream>
using namespace std;
const int N = 5e5 + 10;
int n, k;
int tr[N];
int lowbit(int x) {
return x & -x;
}
int sum(int x) {
int res = 0;
for (int i = x; i; i-= lowbit(i)) res += tr[i];
return res;
}
void add(int s, int x) {
for (int i = s; i <= n; i += lowbit(i)) tr[i] += x;
}
int main() {
scanf("%d%d", &n, &k);
while (k--) {
char op[2];
scanf("%s", op);
if (*op == 'A') {
int x;
scanf("%d", &x);
printf("%d\n", sum(x));
} else {
int s, x;
scanf("%d%d", &s, &x);
if (*op == 'B') add(s, x);
else add(s, -x);
}
}
return 0;
}
每次询问时间复杂度 O ( log n ) O(\log n) O(logn),空间 O ( n ) O(n) O(n)。