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

    题目地址: http://poj.org/problem?id=2352

    分析:

      - 题意分析:  有n个星星, 它的左下方(x和y不超过它)的星星的数目就是它的level, 分别计算level 为 0 到 n-1 的星星的数目. 输入是先按照 y 从小到大排序, 如果y相同,就按照x递增排序, 不会有2个以上星星占同一个坐标.

      - 数据结构

        - 用原始数据数组 a 表示同一个x坐标的星星数目. (a[i]为x坐标为 i-1的星星数目).  注意输入数据时排序的.

        - 树状数组s维护a的信息. 

        - level: level[i] 记录 level为i的星星的数目.

      - 计算

        - 树状数组构建: 由于输入是先按照y排序, 再按照x排序的, 所以不用数组a来构建(最开始a为全0, s也为全0), 而是直接根据输入从无到有更新.

        - 计算level: sumn(int x) 计算了x坐标不大于x的星星的个数, 而按照输入, 计算的时候y值大于当前星星的星星还没有被输入. 所以这个数目就是当前星星的level, 而后面输入的y值不会比这个小, 所以后面的输入, 对当前星星的level不会有改变.

    #include <iostream> 
    #include <cstring>
    using namespace std;  
      
    #define MAX_INDEX_RANGE 32010 // index is from 1.
    
    // 原始数据数组是隐藏的, a[i] 表示x坐标为i的星星数目.
    // s 为维护a数组的树状数组.下标从1 开始. 
    int s[MAX_INDEX_RANGE];
    // level[i] 表示level为i的星星的数目.
    int level[MAX_INDEX_RANGE];
    
    int lowbit(int x){
        return x & (-x);
    }
    
    // 计算x坐标不超过x的星星的总数. 由于是树状数组是动态构建的, 按照输入顺序, y值大于当前星星的还没有被输入, 所以这个数目就是位于当前星星左下方的数目.
    int sumn(int x){
        int sum = 0;
        while(x > 0){
            sum += s[x];
            x -= lowbit(x);
        }
        return sum;
    }
    
    //N: 总的星星的实际数目.
    void modify(int n,int delta,int N){
        // 注意: s[i]的范围是星星坐标的最大值, 因为原始数据数组a表示的是x坐标.
        while(n <= MAX_INDEX_RANGE){ 
            s[n] += delta;
            n += lowbit(n);
        }
    }
    
    int main(){
        int N,x,y,i;
        while(cin>>N){
            memset(s,0,sizeof(s));
            memset(level,0,sizeof(level));
            for(i=0;i<N;++i){
                cin>>x>>y;
                x++; // 因为树状数组坐标从1开始.
                level[sumn(x)]++;
                modify(x,1,N);
            }
            for(i=0;i<N;++i){
                cout<<level[i]<<endl;
            }
        }
        return 0;  
    }
    

     总结:

      - 题目中关键在于找出一维数组a[i]来记录x坐标为 i 的星星的数目. 根据分析, 要求出某个星星左下方的星星数目, 只需求出当前(在它坐标输入的时候)x坐标小于它的星星的数目即可, 也就是要随时查询 x坐标小于等于它的x坐标的星星数目的和. 正好可以用树状数组的统计功能对当前的a[]进行统计. 

      - 树状数组 s 作为一种数据结构比较抽象,没有实际的意义, 仅仅是方便对原始数据数组进行统计和维护. 

      - 树状数组可以用作原始数据数组, 因为s[i]一定包含a[i], 要求a[i] 只需通过计算即可算出来 sumn(i) - sumn(i-1).

  • 相关阅读:
    Sqlite数据库sqlite3命令
    cerr
    include 尖括号和双引号
    C程序存储空间布局——各数据段的内存位置
    贪心算法
    CodeBlocks
    O(n)是什么
    微软公司面试题
    CSS3---结构性伪类选择器—not
    CSS3---结构性伪类选择器-root
  • 原文地址:https://www.cnblogs.com/roger9567/p/4868986.html
Copyright © 2011-2022 走看看