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

     题目简单介绍:

    天空中有一些星星,这些星星都在不同的位置,每个星星有个坐标。

    如果一个星星的左下方(包含正左和正下)有k颗星星,就说这颗星星是k级的。

    求出各个级别的星星的个数。

    首先,引入树状数组,文章摘自http://fqq11679.blog.hexun.com/21722866_d.html

    【引言】

              在解题过程中,我们有时需要维护一个数组的前缀和S[i]=A[1]+A[2]+...+A[i]。

              但是不难发现,如果我们修改了任意一个A[i],S[i]、S[i+1]...S[n]都会发生变化。

              可以说,每次修改A[i]后,调整前缀和S[]在最坏情况下会需要O(n)的时间。

              当n非常大时,程序会运行得非常缓慢。

              因此,这里我们引入“树状数组”,它的修改与求和都是O(logn)的,效率非常高。

    【理论】

              为了对树状数组有个形 象的认识,我们先看下面这张图。

           

              如图所示,红色矩形表示的数组C[]就是树状数组。

              这里,C[i]表示A[i-2^k+1]到A[i]的和,而k则是i在二进制时末尾0的个数,

              或者说是i用2的幂方和表示时的最小指数。

             ( 当然,利用位运算,我们可以直接计算出2^k=i&(i^(i-1)) )

              同时,我们也不难发现,这个k就是该节点在树中的高度,因而这个树的高度不会超过logn。

              所以,当我们修改A[i]的值时,可以从C[i]往根节点一路上溯,调整这条路上的所有C[]即可,

              这个操作的复杂度在最坏情况下就是树的高度即O(logn)。  

              另外,对于求数列的前n项和,只需找到n以前的所有最大子树,把其根节点的C加起来即可。

              不难发现,这些子树的数目是n在二进制时1的个数,或者说是把n展开成2的幂方和时的项数,

              因此,求和操作的复杂度也是O(logn)。

              接着,我们考察这两种操作下标变化的规律:

              首先看修改操作:

              已知下标i,求其父节点的下标。
              我们可以考虑对树从逻辑上转化:

                
             如图,我们将子树向右对称翻折,虚拟出一些空白结点(图中白色),将原树转化成完全二叉树。

             有图可知,对于节点i,其父节点的下标与翻折出的空白节点下标相同。

             因而父节点下标 p=i+2^k  (2^k是i用2的幂方和展开式中的最小幂,即i为根节点子树的规模)

             即  p = i + i&(i^(i-1)) 。

             接着对于求和操作:

             因为每棵子树覆盖的范围都是2的幂,所以我们要求子树i的前一棵树,只需让i减去2的最小幂即可。

             即  p = i - i&(i^(i-1)) 。

            

             至此,我们已经比较详细的分析了树状数组的复杂度和原理。

             在最后,我们将给出一些树状数组的实现代码,希望读者能够仔细体会其中的细节。

    【代码】

      求最小幂2^k:


    int Lowbit(int t)
    {
        return t & ( t ^ ( t - 1 ) );
    }

                 
      求前n项和:


    int Sum(int end)
    {
        int sum = 0;
        while(end > 0)
        {
            sum += in[end];
            end -= Lowbit(end);
        }
        return sum;
    }

     对某个元素进行加法操作: 

    void plus(int pos , int num)
    {
        while(pos <= n)
        {
              in[pos] += num;
              pos += Lowbit(pos);
        }
    }

    pku2352思路:用一个树状数组a[32002];

    每次输入一个坐标i修改相应的a[i]以及a[i+lowbit(i)]......

    该坐标对应的level值就是对坐标小于i的星星做求和操作。

    代码如下:

     

    Code

     

  • 相关阅读:
    angularJS1遍历
    IDEA配置Tomcat
    IDEA配置JDK
    序列化
    servlet,filter,listener,intercepter区别
    textarea文本域值中含有大量 问题
    struts标签与jstl标签互换
    Struts/Hibernate/Spring源码下载
    捕获浏览器关闭、刷新事件,在窗体关闭时从全局对象里移除当前用户
    生成jsp验证码的代码详解(servlet版)
  • 原文地址:https://www.cnblogs.com/pandy/p/1441692.html
Copyright © 2011-2022 走看看