目录
单点修改+区间查询
单点修改仍是模板,区间查询[x,y]时,我们利用前缀和的思想,即(sum[y] - sum[x - 1])即可算出答案
代码
#include<cstdio>
#define M 500000
#define low_bit(x) (x & -x)
#define reg register
inline void read(int &x){
x = 0;
int f = 1;
char s = getchar();
while (s < '0' || s > '9'){
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9'){
x = x * 10 + s - '0';
s = getchar();
}
x *= f;
}
int C[M + 5];
int n,m;
void Add(int x,int y){
for (reg int i = x;i <= n;i += low_bit(i))
C[i] += y;
return ;
}
int Query(int x){
int sum = 0;
for (reg int i = x;i;i -= low_bit(i))
sum += C[i];
return sum;
}
int main(){
read(n),read(m);
for (reg int i = 1;i <= n; ++ i){
int a;
read(a);
Add(i,a);
}
for (reg int i = 1;i <= m; ++ i){
int a,b,c;
read(a),read(b),read(c);
if (a == 1)
Add(b,c);
else printf("%d\n",Query(c) - Query(b - 1));
}
return 0;
}
区间修改 + 单点查询
修改
这里引入差分的思想。
设原数组为A,则差分数组B[i] = A[i] - A[i - 1]
这道题跟差分有什么关系呢?(方便解题呀)
设A[6] = {0,1,2,3,4,5}
则B[6] = {0,1,1,1,1,1}
接着在 2 - 4 区间里每个数加一,则
A[6] = {0,1,3,4,5,5}
B[6] = {0,1,2,1,1,0}
由此,我们可看出 B 数组中,B[2] + 1,B[5] - 1
查询
以上面的例子为例,求A[3]的值(显然为4)
我们进行分析:A[3] = A[3] - A[2] + A[2] - A[1] + A[1] - A[0] = B[3] + B[2] + B[1] = A[3] - A[0] = 4
显然就是求B数组的和
代码
#include<cstdio>
#define M 500000
#define low_bit(x) (x & -x)
#define reg register
inline void read(int &x){
x = 0;
int f = 1;
char s = getchar();
while (s < '0' || s > '9'){
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9'){
x = x * 10 + s - '0';
s = getchar();
}
x *= f;
}
int B[M + 5],A[M + 5];
int n,m;
void Add(int x,int y){
for (reg int i = x;i <= n;i += low_bit(i))
B[i] += y;
return ;
}
int Query(int x){
int sum = 0;
for (reg int i = x;i;i -= low_bit(i))
sum += B[i];
return sum;
}
int main(){
read(n),read(m);
for (reg int i = 1;i <= n; ++ i){
read(A[i]);
Add(i,A[i] - A[i - 1]);
}
for (reg int i = 1;i <= m; ++ i){
int a;
read(a);
if (a == 1){
int x,y,k;
read(x),read(y),read(k);
Add(x,k);
Add(y + 1,-k);
}
else {
int x;
read(x);
printf("%d\n",Query(x));
}
}
return 0;
}
区间修改 + 区间查询
显然修改是不会变的,变的是查询
查询
A[1] + A[2] + A[3] + …+ A[N - 1] + A[N] = B[1] + B[1] + B[2] + B[1] + B[2] + B[3] + … + B[N - 1] + B[N]
= N * B[1] + (N - 1) * B[2] + … + B[N]
= N * (B[1] + B[2] + … + B[N]) - (0 * B[1] + 1 * B[2] + … + (N - 1) * B[N])
因而,我们可以在B数组的基础上再用一个B2数组,令 B2[i] = (i - 1) * (A[i] - A[i - 1])
这样就能很方便的求出答案了。
注: 如果给出区间的左端点 x,不是从一开始的,那么我们可以借鉴 单点修改+区间查询 的前缀和思想(具体操作见代码)
代码
#include<cstdio>
#define lowbit(x) (x & -x)
#define M 100000
#define LL long long
#define reg register
inline void read(int &x){
x = 0;
int f = 1;
char s = getchar();
while(s < '0' || s > '9'){
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9'){
x = x * 10 + s - '0';
s = getchar();
}
x *= f;
}
int n,m;
LL C[M + 5],C2[M + 5];
int A[M + 5];
void update(int x,LL k){
for (reg int i = x;i <= n;i += lowbit(i)){
C[i] += k;
C2[i] += (x - 1) * k;
}
return ;
}
LL query(int x){
LL sum1 = 0,sum2 = 0;
for (reg int i = x;i;i -= lowbit(i)){
sum1 += C[i];
sum2 += C2[i];
}
return sum1 * x - sum2;
}
inline LL Su(int x,int y){
LL sum = query(y);
sum -= query(x - 1);
return sum;
}
int main(){
read(n),read(m);
for (reg int i = 1;i <= n; ++ i){
read(A[i]);
update(i,A[i] - A[i - 1]);
}
for (reg int i = 1;i <= m; ++ i){
int pd;
read(pd);
if (pd == 1){
int x,y,k;
read(x),read(y),read(k);
update(x,k);
update(y + 1,-k);
} else {
int x,y;
read(x),read(y);
printf("%lld\n",Su(x,y));
}
}
return 0;
}