树状数组

树状数组用一个数组C[i]来记录a[i-2^k +1] + ...+a[i]的和,其中k为i在二进制下末尾0的个数。

树状数组能够快速求出数组中连续一段元素的和以及快速修改数组中的元素;

具体实现:

求i在二进制下末尾0的个数;

int  lowbit(int x){
         return x&(-x);
}
或者
int lowbit(int x){
        return x&(x^(x-1));
}

求和:能够快速求a[1] 到a[i]的和,时间复杂度为log(n);

int sum(int i){
      int s = 0;
      for (int  k = i ; k>=0; k -= lowbit(k))
          s +=  c[k];
      return s;
}

 

更新:能在log(n)的时间内更新元素的值(将a[i]的值增加d);

void add(int i,int d){
        for (int k = i; k <= n; k+=lowbit(k)){
               c[k] += d;
        }
}

Uva  12086 树状数组模板题;

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<stack>
#include<string>
#include<set>
#define ll long long
#define  MAX 1000000
#define INF INT_MAX
#define eps 1e-6

using namespace std;

int c[MAX],a[MAX],n;

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

int sum(int i){
      int s = 0;
      for (int  k = i ; k>0; k -= lowbit(k))
          s +=  c[k];
      return s;
}

void add(int i,int d){
        for (int k = i; k <= n; k+=lowbit(k)){
               c[k] += d;
        }
}

int main(){
	char s[10];
	int cas = 0;
	while (scanf("%d",&n) && n != 0){
		memset(c,0,sizeof(c));
		for (int i=1; i<=n; i++){              //树状数组建树方法,通过更新建树,时间复杂度为n*log(n),也有O(n)的方法;
                        scanf("%d",&a[i]);           
			add(i,a[i]);
		}
		
		if (cas) printf("\n");
		cas++;
		printf("Case %d:\n",cas);
		
		int u,v;
		while (scanf("%s",s)){
			if (strcmp(s,"END") == 0) break;
			scanf("%d%d",&u,&v);
			if (s[0] == 'M'){
				printf("%d\n",sum(v) - sum(u-1));
			}
			else {
				add(u,v-a[u]);        //如何更新元素
				a[u] = v;
			}
		}
	}
	return 0;
}
注意:树状数组的下标是从1开始的,而不是从0开始。假如从0开始,则应该满足0 - lowbit(0) < 0,不成立;

二维树状数组:具体实现和一维类似,更新和查询的时间复杂度都是log(n) *log(m);

求和:

int sum(int i,int j){
       int s = 0;
       for (int u = i ; u > 0 ; u -= lowbit(u))
             for (int v = j ; v >=0 ; v -= lowbit(v))
                    s += c[u][v];
       return s;
 }

更新:

void add(int i, int j, int d){
          for (int u = i; u <= n; u += lowbit(u))
               for (int v = j ; v <= m; v += lowbit(v))
                      c[u][v] += d;
}

poj1195 二维树状数组模板题;

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<stack>
#define ll long long
#define MAX 1050
#define INF INT_MAX
#define eps 1e-6

using namespace std;

int c[MAX][MAX];
int n;

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

void add(int i,int j,int d){
	for (int u = i ; u <= n; u += lowbit(u))
		for (int v = j; v <= n; v += lowbit(v))
			c[u][v] += d;
}

int sum(int i, int j){
	int s = 0;
	for (int u = i; u > 0; u -= lowbit(u))
		for (int v = j; v > 0; v -= lowbit(v))
			s += c[u][v];
	return s;
}

int main(){
	int cas;
	while (scanf("%d",&cas) != EOF){
		int x,y,u,v,d;
		if (cas == 0){
			scanf("%d",&n);
			memset(c,0,sizeof(c));
		}
		if (cas == 1){
			scanf("%d%d%d",&u,&v,&d);
			u += 1;
			v += 1;
			add(u,v,d);
		}
		if (cas == 2){
			scanf("%d%d%d%d",&x,&y,&u,&v);
			x += 1;
			y += 1;
			u += 1;
			v += 1;
			printf("%d\n",sum(u,v) - sum(x-1,v) - sum(u,y-1) + sum(x-1,y-1));   //注意如如何输出子矩阵的和 
		}
		if (cas == 3) continue;
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值