树状数组
1. 建树
C1 = A1
C2 = C1 + A2 = A1 + A2
C3 = A3
C4 = C2 + C3 + A4 = A1 + A2 + A3 + A4
C5 = A5
C6 = C5 + A6 = A5 + A6
C7 = A7
C8 = C4 + C6 + C7 + A8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
把对a数组的子序列问题拆分放到C数组,从而实现(longn)求解
建树
int lowbit(x){return x&(-x);}
极致简短!!!现在我们来理解一下这行代码:
我们知道,对于一个数的负数就等于对这个数取反+1
以二进制数11010为例:11010的补码为00101,加1后为00110,两者相与便是最低位的1
其实很好理解,补码和原码必然相反,所以原码有0的部位补码全是1,补码再+1之后由于进位那么最末尾的1和原码
最右边的1一定是同一个位置(当遇到第一个1的时候补码此位为0,由于前面会进一位,所以此位会变为1)
不理解就死记硬背
所以我们只需要进行a&(-a)就可以取出最低位的1了
会了lowbit,我们就可以进行建树了
#include<bits/stdc++.h>
using namespace std;
int a[11],c[11];
int lowbit(int x){return x&(-x);}取出最后一位的1
void add(int k,int v){for(int i=k;i<=10;i+=lowbit(v))c[i]+=v;}更新数组
int main()
{
for(int i=1;i<=10;i++)cin>>a[i],add(i,a[i]);
for(int i=1;i<=10;i++)cout<<c[i]<<endl;
return 0;
5 5+=lowbit(5) 101 2^0=1 5+1=6
6 6+=lowbit(6) 110 6+2=8;
}
--------------------------------------------------------
单点修改&&区间和
单点更新:
继续看开始给出的图
此时如果我们要更改A[1]
则有以下需要进行同步更新
1(001) C[1]+=A[1]
lowbit(1)=001 1+lowbit(1)=2(010) C[2]+=A[1]
lowbit(2)=010 2+lowbit(2)=4(100) C[4]+=A[1]
lowbit(4)=100 4+lowbit(4)=8(1000) C[8]+=A[1]
换成代码就是:
void find(int x,int y,int n){
for(int i=x;i<=n;i+=lowbit(i)) //x为更新的位置,y为更新后的数,n为数组最大值
c[i] += y;
从1--x的前缀和
int getsum(int x){
int ans = 0;
for(int i=x;i;i-=lowbit(i))
ans += c[i];
return ans;
--------------------------------------------------------
例题
题目描述
给出n个数(1 < = n < = 100000 ),并且初始化所有数字都为0.接下来m次操作,( 1<= m < = 100000 )
操作有以下两种:
1: C X K 把第X个数的值增加K(K可正可负)a[X]:=a[X]+K
2: P X Y 就是询问 第X个数至 第Y个数 的所有数的和。 writeln( a[X] + a[X+1] + a[X+2] + …+ a[Y] )
Input
5 3
C 2 3
C 4 5
P 1 5
Output
8
#include<bits/stdc++.h>
#define maxn 150000
using namespace std;
long long a[maxn],c[maxn],n,m;
int lowbit(int x){return x&(-x);}
void add(int k,int v){for(int i=k;i<=n;i+=lowbit(i))c[i]+=v;}
int getsum(int k){int ans=0;for(int i=k;i>=1;i-=lowbit(i))ans+=c[i];return ans;}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,k;
char c;cin>>c>>x>>k;//输入
if(c=='C')add(x,k);//如果是加,那么add
else cout<<getsum(k)-getsum(x-1)<<endl;//求和
}
return 0;
}