树状数组
一、单点修改、区间查询 (~前缀和)
样例输入:
5 5
1 5 4 2 3
1 1 3
2 2 5
1 3 -1
1 4 2
2 1 4
样例输出:
14
16
代码模板:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 500010;
int n,m,a[N];
int lowbit(int x){
return x&(-x);
}
void add(int x,int y){
while(x<=n){
a[x]+=y;
x+=lowbit(x);
}
}
int query(int x)
{
int res=0;
while(x){
res+=a[x];
x-=lowbit(x);
}
return res;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int x;
cin>>x;
add(i,x);
}
while(m--){
int op,x,y;
cin>>op;
if(op==1){
cin>>x>>y;
add(x,y);
}else{
cin>>x>>y;
cout<<query(y)-query(x-1)<<endl;
}
}
return 0;
}
二、区间修改、单点查询(增量作差分)
样例输入
5 5
1 5 4 2 3
1 2 4 2
2 3
1 1 5 -1
1 3 5 7
2 4
样例输出:
6
10
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 500010;
long long n,m,a[N],b[N];
int lowbit(int x){
return x&(-x);
}
void add(int x,int y){
while(x<=n){
b[x]+=y;
x+=lowbit(x);
}
}
int query(int x){
int res=0;
while(x){
res+=b[x];
x-=lowbit(x);
}
return res;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int x;
cin>>a[i];
}
while(m--){
int op;
cin>>op;
if(op==1){
int x,y,k;
cin>>x>>y>>k;
add(x,k),add(y+1,-k);
}else{
int x;
cin>>x;
cout<<query(x)+a[x]<<endl;
}
}
return 0;
}
三、区间修改、区间查询(差分+前缀和)
思路
样例输入
5 10
2 6 6 1 1
2 1 4
1 2 5 10
2 1 3
2 2 3
1 2 2 8
1 2 3 7
1 4 4 10
2 1 2
1 4 5 6
2 3 4
样例输出:
15
34
32
33
50
代码如下:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e6+10;
ll b[N],c[N];
int q[N];
int n,m;
int lowbit(int x)
{
return x&(-x);
}
void add(int u,int x)
{
for(int i=u;i<=n;i+=lowbit(i))
{
b[i]+=x;
c[i]+=(ll)u*x;
}
}
ll query(int x)
{
ll res=0;
for(int i=x;i;i-=lowbit(i))
res+=(x+1)*b[i]-c[i];
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&q[i]);
add(i,q[i]-q[i-1]);
}
while(m--)
{
int f,l,r,x;
scanf("%d",&f);
if(f==1)
{
scanf("%d%d%d",&l,&r,&x);
add(l,x);
add(r+1,-x);
}
else
{
scanf("%d%d",&l,&r);
printf("%lld\n",query(r)-query(l-1));
}
}
return 0;
}