zoukankan      html  css  js  c++  java
  • 浅谈树状数组

    前言

    首先来通过一道题目来展开说明

    已知一个数列,你需要进行下面两种操作:

    1. 将某区间每一个数数加上x
    2. 求出某一个数的值
      数据规模:
      对于30%的数据:N<=8,M<=10
      对于70%的数据:N<=10000,M<=10000
      对于100%的数据:N<=500000,M<=500000

    蒟蒻: 暴力修改
    dalao: 线段树模板题

    这可以用线段树去做,但是线段树的代码量太长了,很容易打错.其实这一题可以用树状数组做.

    概念

    树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。
    这种数据结构(算法)并没有C++和Java的库支持,需要自己手动实现。在Competitive Programming的竞赛中被广泛的使用。树状数组和线段树很像,但能用树状数组解决的问题,基本上都能用线段树解决,而线段树能解决的树状数组不一定能解决。相比较而言,树状数组效率要高很多。

    来自百度百科
    其实树状数组的本质就是进行区间操作,求区间的和,并支持修改操作

    算法讲解

    树状数组从字面上来解释就是树状的数组

    这里的C数组就是树状数组,A数组是原数组
    首先将C数组用A数组表示

    C[1]=A[1];
    C[2]=A[1]+A[2];
    C[3]=A[3];
    C[4]=A[1]+A[2]+A[3]+A[4];
    C[5]=A[5];
    C[6]=A[5]+A[6];
    C[7]=A[7];
    C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];

    通过观察上面的式子我们可以发现一个规律:
    C[i]=A[i-2k+1]+A[i-2k+2]+......A[i];(k为c数组下标的二进制中从最低位到高位连续零的长度)

    但是这个东西我们怎么算呢?

    这时候lowbit就很有用了
    首先来看看lowbit的代码x&(-x)别看代码只有一行实际上是很有用的,他蕴含着许多深意放屁

    实际上lowbit就是计算2^k次方的值
    然后你知道这个就应该知道如何用树状数组了

    code

    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<cstring>
    using namespace std;
    int a[500005*3+10],n,m;
    int lowbit(int x) {
    	return x&(-x);
    }
    inline void add(int x,int c) {
    	while(x<=n) {
    		a[x]+=c;
    		x+=lowbit(x);
    	}
    }
    inline int sum(int x) {
    	int ans=0;
    	while(x>0) {
    		ans+=a[x];
    		x-=lowbit(x);
    	}
    	return ans;
    }
    int main() {
    	int L,x,y;
    	scanf("%d%d",&n,&m);
    	for(int i=1; i<=n; i++) {
    		scanf("%d",&x);
    		add(i,x);
    	}
    	for(int ii=1; ii<=m; ii++) {
    		scanf("%d%d%d",&L,&x,&y);
    		if(L==1)
    			add(x,y);
    		else
    			printf("%d
    ",sum(y)-sum(x-1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    springboot使用mybatis-plus表单更新null值问题通用解决方案
    ASP.NET MVC快速开发框架FastExecutor开发全过程感受及总结
    NetCore实现Transitional自定义注解事物
    NetCore3.0实现自定义IOC容器注入
    ADO.NET事务封装
    ASP.NET MVC模块化开发——动态挂载外部项目
    后台管理tab栏滑动解决方案
    c#使用CefSharp开发winform——环境搭建
    c#通过Redis实现轻量级消息组件
    ASP.NET MVC实现依赖注入
  • 原文地址:https://www.cnblogs.com/hbxblog/p/9866972.html
Copyright © 2011-2022 走看看