树状数组(单点/区间)操作模板

相关讲解链接


单点修改,区间查询(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;
}
posted @ 2020-08-04 17:14  wuwendongxi  阅读(186)  评论(0编辑  收藏  举报