宣传一下算法提高课整理 <—
题目传送门点这里
题目描述
给定长度为 N N N 的数列 A A A,然后输入 M M M 行操作指令。
第一类指令形如 C l r d
,表示把数列中第
l
∼
r
l∼r
l∼r 个数都加
d
d
d。
第二类指令形如 Q x
,表示询问数列中第
x
x
x 个数的值。
对于每个询问,输出一个整数表示答案。
输入格式
第一行包含两个整数 N N N 和 M M M。
第二行包含 N N N 个整数 A [ i ] A[i] A[i]。
接下来 M M M 行表示 M M M 条指令,每条指令的格式如题目描述所示。
输出格式
对于每个询问,输出一个整数表示答案。
每个答案占一行。
数据范围
1
≤
N
,
M
≤
1
0
5
,
1≤N,M≤10^5,
1≤N,M≤105,
∣
d
∣
≤
10000
,
|d|≤10000,
∣d∣≤10000,
∣
A
[
i
]
∣
≤
1
0
9
|A[i]|≤10^9
∣A[i]∣≤109
样例输入
10 5
1 2 3 4 5 6 7 8 9 10
Q 4
Q 1
Q 2
C 1 6 3
Q 2
样例输出
4
1
2
5
思路
这是一道模板题,操作为区间修改,单点查询
,
普通的树状数组处理的是单点修改,区间查询
。
所以我们将原数组进行一次差分,再将差分数组加到树状数组内。
这样,原本树状数组询问的 1 1 1 ~ x x x 的前缀和,就转变为了求 x x x 的值;原本树状数组将一个点加c的操作就转变为了将区间加c。
算法时间复杂度
树状数组每次操作都是 O ( log n ) O(\log n) O(logn) 的复杂度,一共 m m m 次查询
所以时间复杂度大约是 O ( m log n ) O(m \log n) O(mlogn)
AC Code
C + + C++ C++
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int n, m;
int a[N], b[N]; // a是原数组,b是差分数组
int tr[N]; // 树状数组
int lowbit(int x) // 树状数组模板
{
return x & -x;
}
void add(int x, int c)
{
for (int i = x; i <= n; i += lowbit(i))
tr[i] += c;
}
int sum(int x)
{
int res = 0;
for (int i = x; i; i -= lowbit(i))
res += tr[i];
return res;
}
int main()
{
int l, r, d, x;
string op;
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
{
scanf("%d", &a[i]);
b[i] = a[i] - a[i - 1]; // 将原数组变为差分数组
add(i, b[i]); // 将差分数组加入树状数组
}
while (m -- )
{
cin >> op; // 读入操作
if (op[0] == 'C')
{
scanf("%d%d%d", &l, &r, &d);
add(l, d); add(r + 1, -d);
// 第一种情况:区间修改,这是差分的基本操作,将b[l]加c,b[r+1]减c
}
if (op[0] == 'Q')
{
scanf("%d", &x);
int res = sum(x);
printf("%d\n", res);
// 第二种情况:单点查询,相当于求差分数组的前缀和
}
}
return 0;
}
最后,如果觉得对您有帮助的话,点个赞再走吧!