运用1
单点修改,区间查询。
add(pos,x)->在下标 pos 处加上 x
query(pos)->返回 1 到 pos 的前缀和
那么查询区间 [ l , r ]的操作就是query( r ) - query( l - 1 )
例题——洛谷3374
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
const int maxn=500000+10;
int a[maxn];
int n,m;
inline int lowbit(int x){
return x&(-x);
}
inline void add(int pos,int val){
while(pos<=n){
a[pos]+=val;
pos+=lowbit(pos);
}
}
inline int query(int pos){
int res=0;
while(pos>0){
res+=a[pos];
pos-=lowbit(pos);
}
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
add(i,x);//赋初值
}
for(int i=1;i<=m;i++){
int op;
scanf("%d",&op);
if(op==1){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
if(op==2){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",query(y)-query(x-1));
}
}
return 0;
}
运用二
区间修改,单点查询
add 和 query 的操作同运用一,但是使用方式不同:
区间修改(给区间 [ l , r ]加上 d)->
add(l,d);
add(r+1,-d);
单点查询(查询 pos 的值)->
query(pos);
例题——洛谷3368
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
const int maxn=500000+10;
int c[maxn];
int n;
inline int lowbit(int x){
return x&(-x);
}
inline void add(int pos,int val){
while(pos<=n){
c[pos]+=val;
pos+=lowbit(pos);
}
}
inline int query(int pos){
int res=0;
while(pos>0){
res+=c[pos];
pos-=lowbit(pos);
}
return res;
}
int main(){
int m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
add(i,x);
add(i+1,-x);
}
for(int i=1;i<=m;i++){
int op;
scanf("%d",&op);
if(op==1){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,z);
add(y+1,-z);
}
if(op==2){
int x;
scanf("%d",&x);
printf("%d\n",query(x));
}
}
return 0;
}
后记
- 两种运用的add 和 query 完全一样。
- 至于为什么,感觉不好解释,大概是差分的思想,现场手推一下即可。
挖个坑
据说还有一种区间修改区间查询的,过会儿再写。