目錄
單點修改+區間查詢
單點修改仍是模板,區間查詢[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;
}