树状数组(单点/区间)操作模板
相关讲解链接
单点修改,区间查询(loj130/133)
代码(一维)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
long long n,q,c[1000005],a[1000005];
long long lowbit(long long x){return x&(-x);}
void add(long long x,long long d){for(long long i=x;i<=n;i+=lowbit(i)) c[i]+=d;}
long long ask(long long x)
{
long long ans=0;
for(long long i=x;i>0;i-=lowbit(i)) ans+=c[i];
return ans;
}
int main()
{
scanf("%lld%lld",&n,&q);
for(long long i=1;i<=n;++i){scanf("%lld",&a[i]); a[i]+=a[i-1];}
for(long long i=1;i<=q;++i)
{
long long f1,f2,f3; scanf("%lld%lld%lld",&f1,&f2,&f3);
if(f1==1) add(f2,f3);
else printf("%lld\n",ask(f3)-ask(f2-1)+a[f3]-a[f2-1]);
}
return 0;
}
代码(二维)
#include <iostream>
#include <cstdio>
#define maxn 4100
using namespace std;
int c[maxn][maxn],n,m;
int lowbit(int x){return x&(-x);}
void add(int x,int y,int d)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j)) c[i][j]+=d;
}
long long ask(int x,int y)
{
long long ans=0;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j)) ans+=c[i][j];
return ans;
}
int main()
{
scanf("%d%d",&n,&m); int f1,f2,f3,f4,f5;
while(~scanf("%d%d%d%d",&f1,&f2,&f3,&f4))
{
if(f1==1) add(f2,f3,f4);
else scanf("%d",&f5),printf("%lld\n",ask(f4,f5)-ask(f4,f3-1)-ask(f2-1,f5)+ask(f2-1,f3-1));
}
return 0;
}
区间修改,单点查询(loj131)
代码(一维)+(不用差分的 偷懒正解)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
long long n,q,a[1000005],c[1000005];
long long lowbit(long long x){return x&(-x);}
void add(long long x,long long d){for(long long i=x;i<=1000000;i+=lowbit(i)) c[i]+=d;}
long long ask(long long x)
{
long long ans=0;
for(long long i=x;i>0;i-=lowbit(i)) ans+=c[i];
return ans;
}
int main()
{
scanf("%lld%lld",&n,&q);
for(long long i=1;i<=n;++i) scanf("%lld",&a[i]);
for(long long i=1;i<=q;++i)
{
long long f1,f2,f3,f4; scanf("%lld",&f1);
if(f1==1)
{
scanf("%lld%lld%lld",&f2,&f3,&f4);
add(f2,f4); add(f3+1,-f4);
}
else
{
scanf("%lld",&f2);
printf("%lld\n",ask(f2)+a[f2]);
}
}
return 0;
}
代码(一维)+(差分 教科书式解法)+(来源:标题下的链接)
-
查询
设原数组为a[i], 设数组d[i]=a[i]−ai−1,则a[i]=∑ij=1d[j],可以通过求d[i]的前缀和查询。
-
修改
当给区间[l,r]加上x的时候,a[l] 与前一个元素 a[l−1] 的差增加了x,a[r+1] 与 a[r] 的差减少了x。根据d[i]数组的定义,只需给d[l] 加上 x, 给d[r+1] 减去 x 即可。
-
代码片段
void add(int p, int x){ //这个函数用来在树状数组中直接修改
while(p <= n) sum[p] += x, p += p & -p;
}
void range_add(int l, int r, int x){ //给区间[l, r]加上x
add(l, x), add(r + 1, -x);
}
int ask(int p){ //单点查询
int res = 0;
while(p) res += sum[p], p -= p & -p;
return res;
}
区间修改,区间查询(POJ3468/loj135)
代码(一维)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
long long n,q,a[100005],sum1[100005],sum2[100005];
long long lowbit(long long x){return x&(-x);}
void add(long long x,long long d)
{
for(long long i=x;i<=n;i+=lowbit(i))
{
sum1[i]+=d;
sum2[i]+=d*(x-1);
}
}
long long ask(int x)
{
long long ans=0;
for(long long i=x;i>0;i-=lowbit(i)) ans+=x*sum1[i]-sum2[i];
return ans;
}
int main()
{
scanf("%lld%lld",&n,&q);
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
add(i,a[i]-a[i-1]);
}
while(q--)
{
char f; long long f1,f2,f3; cin>>f;
if(f=='Q')
{
scanf("%lld%lld",&f1,&f2);
printf("%lld\n",ask(f2)-ask(f1-1));
}
else if(f=='C')
{
scanf("%lld%lld%lld",&f1,&f2,&f3);
add(f1,f3); add(f2+1,-f3);
}
}
return 0;
}
代码(二维)
维护:d[i][j],d[i][j]∗i,d[i][j]∗j,d[i][j]∗i∗j (d[i][j]为a[i][j]差分数组)
#include <iostream>
#include <cstdio>
#define int long long
#define maxn 2050
using namespace std;
int n,m,sum1[maxn][maxn],sum2[maxn][maxn],sum3[maxn][maxn],sum4[maxn][maxn];
int lowbit(int x){return x&(-x);}
void add(int x,int y,int d)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
{
sum1[i][j]+=d;
sum2[i][j]+=x*d;
sum3[i][j]+=y*d;
sum4[i][j]+=x*y*d;
}
}
int ask(int x,int y)
{
int ans=0;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j))
ans+=(x+1)*(y+1)*sum1[i][j]-(y+1)*sum2[i][j]-(x+1)*sum3[i][j]+sum4[i][j];
return ans;
}
void addedge(int xa,int ya,int xb,int yb,int d){
add(xa,ya,d),add(xa,yb+1,-d),add(xb+1,ya,-d),add(xb+1,yb+1,d);
}
int askedge(int xa,int ya,int xb,int yb){
return ask(xb,yb)-ask(xb,ya-1)-ask(xa-1,yb)+ask(xa-1,ya-1);
}
signed main()
{
scanf("%lld%lld",&n,&m);
int op,f1,f2,f3,f4,f5;
while(~scanf("%lld%lld%lld%lld%lld",&op,&f1,&f2,&f3,&f4))
{
if(op==1) scanf("%lld",&f5),addedge(f1,f2,f3,f4,f5);
else printf("%lld\n",askedge(f1,f2,f3,f4));
}
return 0;
}