树状数组实现线段树区间修改区间查询功能

版权声明:如果路过的各位大佬想对菜鸡进行指点请加QQ:3360769137 https://blog.csdn.net/PleasantlY1/article/details/84345964

         已知树状数组区间修改单点查询时tree数组中存放的是相邻差值,那么区间修改的基础我们已经有了,但只能支持单点查询,需要再构造区间查询功能,暴力累加是不可能考虑的,而树状数组的区间查询是利用前缀和实现的,tree数组中存储的是前缀和。所以我们需要在单点查询的基础上再构造一个前缀和。我们需要整理一下查询

第k个数 a[k]=tree[1]+tree[2]+tree[3]+tree[4]+...+tree[k]

第k的前缀和为 s[k]=a[k]+a[k-1]+....+a[1]

即为 s[k]=(tree[1]+tree[2]+...tree[k])+(tree[1]+tree[2]+...+tree[k-1])+...+(tree[1])

拆分合并即为 s[k]=tree[1]*k+tree[2]*(k-1)+....+tree[k]*1

虽然这是一个和的形式,但是无法直接构造,因为与当前位置无直接关系,需要构造一个。

转化成包含普通前缀和的形式

s[k]=k*(tree[k]+tree[k-1]+...+tree[1])-(tree[k]*(k-1)+tree[k-1]*(k-2)+tree[k-2]*(k-3)+....+tree[1]*0)

前部分可以直接使用tree数组查询,观察后部分为tree[i]*(i-1)的前缀和形式,所以另设置一个树状数组p来存储。

初始化为 add(i,(i-1)*y)     y为原数组的差分即当前元素与上一个元素的差值即tree[y]

区间修改时无异  add(x,k*(y-1))   add(y+1,-k*y)

所以所求的区间(x,y)和为 【y*y的tree前缀和-(x-1)*(x-1tree的前缀和)】-【y的p前缀和-x的p前缀和】

(y*sum(y,tree)-(x-1)*sum(x-1,tree))-(sum(y,p)-sum(x-1,p))

实际上就是利用前缀和构造。不能就转化成前缀和形式

代码如下:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define INF 0x3f3f3f3f
#define ll long long
#define per(i,a,b) for(int i=a;i<=b;++i)
ll int n,m,tree[2000010],p[2000010];
ll int lowbit(ll int k)
{
	return k&(-k);
}
void add(ll int x,ll int k,int fag)
{
	while(x<=n)
	{
		if(fag==1) tree[x]+=k;
		else p[x]+=k;
		x+=lowbit(x);
	}
}
ll int sum(ll int x,int fag)
{
	ll int s=0;
	while(x!=0)
	{
		if(fag==1) s+=tree[x];
		else s+=p[x];
		x-=lowbit(x);
	}
	return s;
}
int main()
{
	scanf("%lld%lld",&n,&m);
	ll int x,y=0;
	per(i,1,n) 
	{
		//ll int x,y;
	    scanf("%lld",&x);
	    y=x-y;
	    add(i,y,1);//区间查询单点修改,前缀和为该位置的值 
	    add(i,(i-1)*y,2);//前缀和差值部分 
	    y=x;
	} 
	per(i,1,m)
	{
		ll int a,b,c,d;
		scanf("%lld",&a);
		if(a==1)
		{
			scanf("%lld%lld%lld",&b,&c,&d);
			add(b,d,1);add(c+1,-d,1);//正常的插入 
			add(b,d*(b-1),2);add(c+1,-d*c,2);//正常的维护 
		}
		if(a==2)
		{
			scanf("%lld%lld",&b,&c);
			printf("%lld\n",(c*sum(c,1)-(b-1)*sum(b-1,1))-(sum(c,2)-sum(b-1,2)));
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/PleasantlY1/article/details/84345964