树状数组
作者:互联网
先上板子,之后再写解析
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; }
标签:const,树状,int,updata,cin,数组,ans,bit 来源: https://www.cnblogs.com/lastonepersonwhohavebitenbycompanies/p/10908358.html