码迷,mamicode.com
首页 > 编程语言 > 详细

树状数组

时间:2019-05-22 20:52:29      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:ios   树状   树状数组   ons   适合   符号   main   out   差分   

先上板子,之后再写解析

1.单点查询、区间求和

 1 #include<iostream>
 2 using namespace std;
 3 const int inf=0x3f3f3f3f;
 4 const int max_n=1<<16;
 5 int bit[max_n];
 6 //获取 i的二进制最低位非0为对应的二进制数 
 7 //比如0101获取就是0001;0110获取就是0010 
 8 int lowbit(int i){
 9     return i&(-i);//-t 代表t的负数 计算机中负数使用对应的正数的补码来表示
10                                         //负数的补码是:除符号位外,各位取反,然后总体+1。 
11                  // t=6(0110) 此时 k=1
12                 //-t=-6=(1001+1)=(1010)    
13 }
14 //查询 
15 int getsum(int n){//sum[i]=bit[i]+bit[i-2^k1]+bit[i-2^k2]+...;
16                 //k1=i-lowbit(i);k2=k1-lowbit(k1);k3=k2-lowbit(k2);...;
17     int sum=0;
18     //比如求sum[7]=bit[7]+bit[6]+bit[4]
19     //                    bit[111]+bit[110]+bit[100]// +bit[000]
20     //从bit[n]开始加,每加一个数, i的二进制就减去i的二进制最低为非0为对应的二进制数 
21     //比如bit[110]=bit[111-001];bit[100]=bit[110-010]; 
22     for(int i=n;i>0;i-=lowbit(i)){
23         sum+=bit[i];
24     }
25     return sum;
26 }
27 //更新 
28 void updata(int n,int x){
29     //更新数组,其中二进制对应变换是查询的逆过程,从低位到高位
30 //比如n=5,x=1;  bit[5]+=1;  bit[6]+=1;                   bit[8]+=1;
31     //            bit[0101];  bit[0110]=bit[0101+0001];     bit[1000]=bit[0110+0010];
32     for(int i=n;i<=max_n;i+=lowbit(i)){
33         bit[i]+=x;
34     }
35 }
36 //适合单点更新和区间查询 
37 int main(){
38     
39     return 0;
40 } 

2.区间更新、单点求和

 1 #include<iostream>
 2 using namespace std;
 3 const int max_n=1<<16;
 4 //适合区间更新和单点查询 
 5 int A[max_n]={0};//原数组 
 6 int bit[max_n]={0};//树状数组 
 7 //设置一个虚拟中间数组D[]; 
 8 //A[i]=D[1]+D[2]+...+D[i]; 
 9 //D[i]=A[i]-A[i-1];
10 //A[]: 1 3 4 4 5 6 
11 //D[]: 1 2 1 0 1 1
12 //当A[x=2---y=5]加上2时:
13 //A[]: 1 5 6 6 7 6
14 //D[]: 1 4 1 0 1 -1
15 //只有D[x]加上了2,D[y+1]减去了2 
16 
17 //所以用D[]来初始化bit[]数组 
18 
19 int lowbit (int i){
20     return i&(-i);
21 }
22 void updata(int n,int k){
23     for(int i=n;i<max_n;i+=lowbit(i)){
24         bit[i]+=k;
25     }
26 }
27 int getsum(int i){
28     int ans=0;
29     while(i>0){
30         ans+=bit[i];
31         i-=lowbit(i);
32     }
33     return ans;
34 }
35 int main(){
36     int n,x,y,k,z;
37     cin >> n;
38     for(int i=1;i<=n;i++){
39         cin >> A[i];
40         updata(i,A[i]-A[i-1]);//需要构造D[]数组差分来创建bit[]数组 
41     }    
42     cin >> x >> y>> k;
43     //x---y区间更新 
44     updata(x,k);//D[x]+k; 
45     updata(y+1,-k);//D[y+1]-k;
46     cin>>z;//输入查询的单点
47     cout << getsum(z);
48     return 0;
49 }

3.区间更新和区间求和

#include<iostream>
using namespace std;
const int max_n=1<<16;
//接上一次
//适合区间更新和区间求和
int A[max_n]={0};
int bit[max_n]={0};//还是需要创建差分 
//具体思路接上一次 
//求和的话:
//A[1]+A[2]+...+A[i]=D[1]+( D[1]+D[2] )+...+( D[1]+D[2]+...+D[i] )
//                    =i*D[1]+(i-1)*D[2]+...+D[i];
//                    =i*( D[1]+D[2]+...+D[i] )-( 0*D[1]+1*D[2]+...+(i-1)*D[i] );
//        n           n          n
//所以 ∑ A[i]=n* (∑ D[i]) - ∑( D[i]*(i-1) );
//      i=1         i=1        i=1
//所以除了bit[]数组存D[]
//再用bitelse[]数组存D[i]*(i-1)
int bitelse[max_n]={0}; 
int lowbit(int i){
    return i&(-i);
}
void updata(int i,int k){
    int x=i;//因为bitelse[]是树状数组,所以要保存初始i; 
    //        更新一个值,其他的bitelse也要更新相同的值 
    while(i<max_n){
        bit[i]+=k;
        bitelse[i]+=k*(x-1);
        i+=lowbit(i);
    }
}
int getsum(int i){
    int ans=0,x=i;
    while(i>0){
        ans+=x*bit[i]-bitelse[i];
        i-=lowbit(i);
    }
    return ans;
}
int main(){
    int n,x,y,k,z;
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> A[i];
        updata(i,A[i]-A[i-1]);
    }
    cin >> x >> y >> k;
    updata(x,k);//更新D[x];
    updata(y+1,-k);//更新D[y+1]
    int sum=getsum(y)-getsum(x-1);
    cout << sum;//求x---y区间的和 
    return 0;
}

 

树状数组

标签:ios   树状   树状数组   ons   适合   符号   main   out   差分   

原文地址:https://www.cnblogs.com/lastonepersonwhohavebitenbycompanies/p/10908358.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!