树状数组(改段求点) ,洛谷之提高历练地,提高模板-nlogn数据结构

版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢 https://blog.csdn.net/Deep_Kevin/article/details/79970915

正题

      该段求点看似很难,如果我们可以一次性把i到n都加上某个数就好了~~

      不难想到用差分的思想,我们每次处理一下当前这个数与前面一个数的差值,那么通过统计这个数组的前缀和就可以完成我们的操作。

      比如说我们用一个diff[i]来表示i与i-1的差值,那么p[i]=sigma(diff[j])(j=[1~n]);想想是不是。

      那么sigma这个操作我们用树状数组来维护前缀即可。

      我们给一个diff[i]+k那么就表示着给i到n都加上了k。因为差分传递的。。。。

      改段〉〉??? 不对,因为你有一个左节点(x)和一个右节点(y),你给diff[x]+k当然也要给diff[y+1]-k。因为你给y+1到n也加上了k,当然要减去。

      理解了就搞一搞树状数组维护

#include<cstdio>
#include<cstdlib>
#include<cstring>

int n,m;
int tot[500010];

int lowbit(int x){
	return x&(-x);
}

void add(int x,int t){
	while(x<=n){
		tot[x]+=t;
		x+=lowbit(x);
	}
}

long long get_tot(int x){
	long long t=0;
	while(x>=1){
		t+=tot[x]; 
		x-=lowbit(x);
	}
	return t;
}

int main(){
	scanf("%d %d",&n,&m);
	int last,x;
	scanf("%d",&last);
	add(1,last);
	for(int i=2;i<=n;i++){
		scanf("%d",&x);
		add(i,x-last);//diff数组初始化,因为是这个数和上一个数的差
		last=x;
	}
	for(int i=1;i<=m;i++){
		int t,x,y,z;
		scanf("%d %d",&t,&x);
		if(t==1) scanf("%d %d",&y,&z),add(x,z),add(y+1,-z);//x,y在这里
		else printf("%lld\n",get_tot(x));//求前缀和
	}
}

阅读更多
换一批

没有更多推荐了,返回首页