树状数组

树状数组和线段树很像,同样也是解决区间的问题

图解

树状数组_第1张图片

0001 C1 = A1
0010 C2 = A1 + A2
0011 C3 = A3
0100 C4 = A1 + A2 + A3 + A4
0101 C5 = A5
0110 C6 = A5 + A6
0111 C7 = A7
1000 C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8

要求Cn,记下标n的二进制末位0的个数为k,可看出,它的管辖区间为2的k次方。

模版

int lowbit(int x){//利用补码的特性算出二进制末位0的个数 
	return x&(-x);
}

void update(int x,int v){//从低到高更新节点值 
	while(x<=n){
		tree[x]+=v;
		x+=lowbit(x);//跳出下标x的管辖范围 
	}
}

int getsum(int x){//从高到低获取前n项和 
	int sum=0;
	while(x>0){
		sum+=tree[x];
		x-=lowbit(x);
	}
	return sum;
}
应用

题源  hdu 1166

#include
using namespace std;
const int maxn = 1e5 + 5;
int tree[maxn];
int N;
//hdu 1166

int lowbit(int x){
	return x&(-x);
}

void update(int x,int v){
	while(x<=N){
		tree[x]+=v;
		x+=lowbit(x);
	}
}

int getsum(int x){
	int sum=0;
	while(x>0){
		sum+=tree[x];
		x-=lowbit(x);
	}
	return sum;
}

int main(){
	int T;
	char cmd[10];
	scanf("%d",&T);
	for(int i=1;i<=T;i++){
		scanf("%d",&N);
		for(int j=1;j<=N;j++){
			int v;
			scanf("%d",&v);
			update(j,v);
		}
		printf("Case %d:\n",i);
		while(~scanf("%s",cmd)&&strcmp(cmd,"End")){
			int x,y;
			scanf("%d%d",&x,&y);			
			if(strcmp(cmd,"Query")==0){
				int ans=getsum(y)-getsum(x-1);
				cout<


你可能感兴趣的:(算法)