树状数组

前置芝士
电脑存数时用二进制(废话),正常环境下int占4字节,一字节含8比特位,数据范围在-2147483648 ~2147483648 之间,加上unsigned不管负数就可以开到4294967296,long long 更狠,开到
-9223372036854775807~9223372036854775807
 
树状数组
这玩意儿给我留下最大的阴影在于不知道lowbit是怎么用的。。。鉴于电脑存负数依赖补码(反码加一),x&(-x)做的j就是这件事。还有就是差分数组(差分(1)=原数组(1))的思想:差分与前缀和是互逆操作,就是说差分数组的前缀和就是原数组。在树状数组里差分用于预处理父亲节点、子节点的关系
#include<bits/stdc++.h>
using namespace std;
int n,s[1000010],m;
int lowbit(int x){ return x&(-x); }

struct node
{
	int c[1000010];
	void init()
	{
		memset(c,0,sizeof(c));
		for(int i=1;i<=n;i++)
			for(int j=i-lowbit(i)+1;j<=i;j++)
				c[i]=c[i]+s[j];
	}
	void add(int x,int d)
	{
		s[x]+=d;
		for(int i=x;i<=n;i+=lowbit(i)) c[i]+=d;
	}
	int sum(int x)
	{
		int ans=0;
		for(int i=x;i>0;i-=lowbit(i)) ans+=c[i];
		return ans;
	}
}a;

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&s[i]);
	}
	a.init();
	for(int i=1;i<=m;i++)
	{
		int k,x,y;
		scanf("%d%d%d",&k,&x,&y);
		if(k==1) a.add(x,y);
		else printf("%d\n",a.sum(y)-a.sum(x-1));
	}
	return 0;
}

 

#include<bits/stdc++.h>
using namespace std;
int n,m,l,r,x;
long long c[500010],k,a;
int lowbit(int x){
    return x&(-x);
}
void change(int x,long long y){
    while(x<=n){
        c[x]+=y;
        x+=lowbit(x);
    }
}
long long solve(int x){
    long long cnt=0;
    while(x){
        cnt+=c[x];
        x-=lowbit(x);
    }
    return cnt; 
}
int main(){
    scanf("%d%d",&n,&m);
    long long now=0;
    for(int i=1;i<=n;i++){
        scanf("%lld",&a); 
        change(i,a-now);
        now=a;//更新
    }
    while(m--){
        scanf("%d",&x);
        if(x==1){
            scanf("%d%d%lld",&l,&r,&k);
            change(l,k); 
            change(r+1,-k); 
        }
         else{
            int s;
            scanf("%d",&s);
            printf("%lld\n",solve(s));//求和
        }
    }
    return 0;
}

 

posted @ 2022-02-13 12:43  fervency  阅读(21)  评论(0编辑  收藏  举报