树状数组
前置芝士
电脑存数时用二进制(废话),正常环境下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;
}