zoukankan      html  css  js  c++  java
  • 树状数组小结

    树状数组必要的图解


    这个图表示了对数组的变化。使得 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[i]的值代表了相应的i能够控制的区间,那么假设改变一个值后,仅仅须要改变c数组中控制这个区间的c[i]就能够了

    1.树状数组。两个最主要的操作,改动和查询

    首先的条件是神一样的函数

    int c[100010] ;

    int lowbit(int x)
    {
        return x&-x;
    }这个函数能够使 i-=lowbit(i) 跳到i控制的区间的之前的节点  i += lowbit(i) 跳到i控制区间的之后的节点 ,也就是说能够由i跳到下一个控制区间包含i的位置

    改动

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

    查询

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

    在这个改动中由前向后改动。改变了全部c数组中控制区间包括i的值,查询时有后向前搜索。log(n)的时间搜索到整个的值


    2. 在树状数组中不仅能够改动一个值,也能够改动区间内的全部值

    1.假设每次查询的是数组中某一个值,那么用树状数组比线段树更省时间,例。假设要改动[x,y]内的值。能够用数组a保留初始的情况,数组b表示改动的情况(b[i]表示,由i到n的全部数+b[i]),那么对于[x,y]就能够表示成 b[x] += 1 , b[y+1] += -1 ;这样由b数组写出的树状数组中,对于计算i时,由b[1] + b[2] + b[3] 。

    。b[i] 表示了对i全部的改动

    2.假设查询的是一段区间和。也可用树状数组写出。同上一样数组a保留初始情况。数组b表示改动的情况(b[i]表示由i到n的全部改动),那么求区间[x,y]的和时 sum = Sy - Sx。以Sx为例  Sx = 初始值+改动的值,改动的值 = b[1] * x + b[2] * (x-1) + 。。b[x]*1 = ( x+1 )*(b[1]+b[2]。。+b[x]) - ( b[1]*1 + b[2]*2 + 。

    b[x]*x ) 用两个树状数组表示b[i]的和。b[i]*i的和

    3 二维的树状数组

    二维的树状数组的改动和查询操作

    改动

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

    查询

    int sum(int i,int j)
    {
        int a = 0 , x , y ;
        for( x = i ; x > 0 ; x -= lowbit(x) )
            for( y = j ; y > 0 ; y -=lowbit(y) )
                a += c[x][y] ;
        return a;
    }

    原理同一维同样,只是在二维中c[i][j] 表示由[1,1]到[i,j]的矩形的和

    相同在改动一个值时,能够方便的查询出一段区间的和。改动一段区间时,方便的查询一个数的值

    3, 三维树状数组

    改动

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

    查询

    int sum(int i,int j,int k)
    {
        int a = 0 , x , y , z ;
        for(x = i ; x > 0 ; x -= lowbit(x))
            for(y = j ; y > 0 ; y -= lowbit(y))
                for(z = k ; z > 0 ; z -= lowbit(z))
                    a += c[x][y][z];
        return a ;
    }

    使用方法同上


    4.例题

    1.poj2481。对s和e排序,保证对于第i头牛时,全部比i强壮的牛都统计过,而且对于标记的数组来说在i的前面。方便用树状数组统计前面的数量

    2.poj2352。星的问题,同上一样,使得每一个等级比它小的都会在它之前统计过

    3.poj2299。对问题的转化,问须要多少次交换。能够转化为从第一个開始每次都是它之前的变为有序的。那么对于第i个仅仅须要交换在i之前的,且比i大的,题目就转化为求逆序数的问题,使用树状数组求逆序数,能够向前统计比它小的个数。用(i-sum)求出i之前比它大的数目,或者直接向后统计,比他大的数目

    4.hdu1556。每次改动了一段范围的值,问某一个数的值

    5.poj2182,杂乱的牛站到一起。给出的数表示在该牛之前有多少序号比该牛小的,由后向前统计,那么第i个牛的序号 = 在还无用的序号,找出第a[i]+1个,使用树状数组计算序号为k是当前的第几个。使用二分找到第a[i]+1个,那个序号就是牛a[i]的序号。

    (注意为了防止一个序号被用多次,找到的序号尽可能的向左)

    6.poj3468,树状数组解法

    7.poj2155,二维树状数组,改动一个矩形的数,问某个数的大小

    8.hdu3584。三维树状数组,同上。

  • 相关阅读:
    Redux 学习总结
    ECMAScript 6 学习总结
    Bootstrap 前端UI框架
    React.js 学习总结
    html 之 <meta> 标签之http-equiv
    Leetcode Excel Sheet Column Number (C++) && Excel Sheet Column Title ( Python)
    490
    414
    494
    458
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/7079981.html
Copyright © 2011-2022 走看看