HDU1166 树状数组

题目链接

初始给一个数组,然后对这个数组中的元素进行加减操作,比如add i x,就是把数组中第i个元素加x;sub减法就可以看做是加了一个负数;然后要完成一个查询操作,比如query a b(b>a),就是要查询数组中第a个元素到第b个元素的和(区间和)

普通的做法就是建立一个数组,直接加减求和,加减都可以直接O(1)完成,但是区间求和的过程比较麻烦,需要O(n)的复杂度;

所以我们建立一个树状数组,来以较低的复杂度完成区间求和这个操作。

首先引入lowbit这个函数,定义 lowbit(i)=i&(-i) 

然后我们构建树状数组c,假设我们原有的数组是a数组(其实不存在),那么,c[i]表示从a[i-lowbit(i)]到a[i]这lowbit(i)个数的和。

为了方便描述,我copy了一点描述过来:


如上图所示

c1 = a1

c2 = a1 + a2

c3 = a3

c4 = a1 + a2 + a3 + a4

c5 = a5

c6 = a5 + a6

c7 = a7

c8 = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8

对于序列a,我们设一个数组C定义C[i] = a[i – 2^k + 1] + … + a[i] , k=lowbit(i)(这是为啥我也不知道)


具体的我也没太理解,但是可以简单的用两个add和sum函数来描述树状数组的一些操作,如下:

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

void add(int x, int y){
	while(x<=n){
		c[x]+=y;
		x+=lowbit(x);
	}
	return ;
}

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

相信我虽然现在不太理解,多写几次应该就理解了吧!:D

顺便贴上完整ac代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int maxx=50010;

int c[maxx];
int n;

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

void add(int x, int y){
	while(x<=n){
		c[x]+=y;
		x+=lowbit(x);
	}
	return ;
}

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

int main (){
	int T,x,y,xu=1;
	string s;
	cin>>T;
	while(T--){
		memset(c, 0, sizeof(int)*maxx);
		printf("Case %d:\n",xu++);
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>x;
			add(i,x);
		}
		while(1){
			cin>>s;
			if(s[0]=='E') break;
			else if(s[0]=='A'){
				cin>>x>>y;
				add(x,y);
			} 
			else if(s[0]=='S'){
				cin>>x>>y;
				add(x,-y);
			}
			else if(s[0]=='Q'){
				cin>>x>>y;
				cout<<sum(y)-sum(x-1)<<endl;
			}
		}
	}
	return 0;
}

错点:

1.memset操作要在while(T--)里面进行,因为每一次的数组都是不一样的初始值,每次操作前都要初始化c数组

猜你喜欢

转载自blog.csdn.net/qq_33982232/article/details/80788716
今日推荐