zoukankan      html  css  js  c++  java
  • 简单的树状数组

    简介

    树状数组和线段树相比而言,树状数组的代码量明显偏少,仅对于单点修改或者是求前缀和之类的题目,树状数组真的是不二之选.


    原理


    如图所示,上面参差不齐的c数组管理着下面的a数组.
    显然,c[2]管理的是a[1]、a[2],共2个;
    c[4]管理的是a[1]、a[2]、a[3]、a[4],共4个;
    c[6]管理的是a[5]、a[6],共2个;
    c[8]管理的是a[1]到a[8],共8个;(全是2的多次方对不对,保持悬念就好了)
    所以,如果要计算区间和的话,比如说a[100]到a[200],暴力完全可以,但如果是a[1000000]到a[10000000]的话,那就直接爆了.
    而使用树状数组求区间和,则颇为方便,下面再作详细解答.


    用法及操作

    对于c数组中的每一个元素它所管理的元素个数,我们通过观察可以发现,在数值上它等于该元素的下标的二进制表示的从右往左数第一个“1”的权值。
    举例1,c[8]的下标8二进制表示为1000,从右往左数第一个“1”在第4位,权值为pow(2,3)即8;
    举例2,c[6]的下标6二进制表示为110,从右往左数第一个“1”在第2位,权值为pow(2,1)即2;
    很清楚了,我们用lowbit来表示c数组中元素所管理的元素个数,通过前面的分析,这个lowbit要表示的是它二进制表示下最后一个“1”的权值,那么这个最后一个“1”的位置怎么得到呢?
    举例x1=11001001000,我们将它取反,
    得到x2=00110110111(前置0不清空),这个时候再+1,
    得到x2=00110111000,这样子,x1&x2不就得到了1000么,不就表示的是lobit值么.总结上述得到lowbit(x)=x&(-x),-x表示的是x的二进制表示取反并+1,数值上等于x(x—1),(其中是异或);

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

    清楚lowbit之后,那么对于单点修改就轻松了;

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

    每次把上级都更新好了就行.
    区间和也简单吧.

    int getsum(int x)
    {
    	int ans=0;
        while(x>=1)
        {
        	ans+=c[x];
            x-=lowbit(x);
        }
    }
    

    相比于区间修改以及区间查询,本人更喜欢使用线段树,而对于树状数组而言这两种操作使用差分思想也是可以做到的,就这样吧。
    贴个区间修改区间查询的链接:

  • 相关阅读:
    iOS开发之Xcode8兼容适配iOS 10资料整理笔记
    C#流概述
    C#回调实现的一般过程
    ASP.Net MVC的学习
    RAID基本知识
    Infiniband基本知识
    [转]开源实时视频码流分析软件:VideoEye
    [转]高分一号的落后与特色
    [转]MVC,MVP 和 MVVM 的图示
    图文助你打开MS SQL Serever的ldf和mdf文件
  • 原文地址:https://www.cnblogs.com/cancers/p/11021350.html
Copyright © 2011-2022 走看看