转载自 http://www.cnitblog.com/cockerel/archive/2006/09/13/16806.html

相信对算法设计或者数据结构有一定了解的人对线段树都不会太陌生。它是能够在log(MaxLen)时间内完成线段的添加、删除、查询等操作。但一般的实现都有点复杂(我自写的是要递归的,比较多行)。而线段树应用中有一种是专门针对点的。(点树?)它的实现却非常简单。
  这种数据结构有什么用?我们先来考虑一下下面的需求(全部要求在LogN时间内完成):如何知道一个点在一个点集里的大小“排名”?很简单,开一个点数组,排个序,再二分查找就行了;如何在一个点集内动态增删点?也很简单,弄个平衡树就行了(本来平衡树比线段树复杂得多,但自从世界上有了STL set这么个好东东,就……^_^)那如果我既要动态增删点,也要随时查询到一个点的排名呢?那对不起,可能就要出动到我们的“点树”了。
  其实现原理很简单:每当增加(或删除)一个大小为X的点时,就在树上添加(或删除)一条(X,MaxLen)的线段(不含端点),当要查询一个点的排名时,只要看看其上有多少条线段就可以了。针对这一需求,这里有个非常简单的实现(见以下代码,十多行,够短了吧?)其中clear()用于清空点集;add()用于添加一个点;cntLs()返回小于n的点的个数,也就是n的升序排名,类似地cntGt是降序排名。
  这个点树有什么用呢?其中一个应用时在O(NlogN)时间内求出一个排列的逆序数(http://acm.zju.edu.cn/show_problem.php?pid=1484,你有更好的算法吗?欢迎交流)方法是每读到一个数x,就让逆序数+=cntGt(x);然后再add(x)。
  这个实现还可以进行一些扩展。比如删除del(int n),只要把add(int n)中的++size换成--size,把a[i/2]++改成a[i/2]--即可。另外还可以通过二分查找功能在O(logN)时间内查到排名第n的点的大小。应该也可以三四行内搞定。

 template < int  N > // 表示可用区间为[0,N),其中N必须是2的幂数;  
 class  PointTree {
     int  a[ 2 * N];
     int  size; 
     void  clear() { memset( this , 0 , sizeof ( * this ));}  
     void  add( int  n) {
         int  i = N + n;  ++ size; 
         for ( ++ a[i]; i > 1 ; i /= 2 )
             if ( ~ i & 1 ) a[i / 2 ] ++ ;
    }  
     int  cntLs( int  n) { // 统计小于  
          int  i = N + n,c = 0 ;  // 若统计小于等于则c=a[i];  
          for (; i > 1 ; i /= 2 ) 
             if (i & 1 ) c += a[i / 2 ];
          return  c;
    } 
      int  cntGt( int  n) {  return  size - a[N + n] - cntLs(n); }  
} ; 

  嗯~~~为了解http://acm.zju.edu.cn/show_problem.php?pid=2425这一题,还是把上述两个扩展给实现了啦,果然不难:

(接上)
    void del(int n){
        if(!a[n+=N])return;
        --size;
        for(--a[n]; n>1; n/=2)
            if(~n&1)--a[n/2];
    }
    /*  解决:求点集中第i小的数(由0数起)
     *    注意:如果i>=size 返回N-1 
     */ 
    int operator[](int n){
        int i=1;
        while(i<N){
            if(n<a[i]) i*=2;
            else n-=a[i], i=i*2+1;
        }
        return i-N;    
    }    
};  
//附一个测试程序
#include<iostream.h>
T<8192> t;  
int main(){
    char c; int n;
    while(cin>>c){
           if(c=='c') t.clear();
           else{
               cin>>n;
               if(c=='a') t.add(n);
               if(c=='d') t.del(n);
               if(c=='q') cout<<t[n]<<endl;
           }    
    }    
               
    return 0;
}  

求点集里n的个数了!

int cntEQ(int n){
    return a[N+n];
}

P.S.:
  在写完这篇文章一段时间后,我认识了另一种功能上比较类似的数据结构,叫做“树状数组”。它们有不少相似之处:

  • 针对点集的处理(添加、删除、查找);
  • 相似的时空复杂度(logN时间,2N空间);
  • 相似的编程复杂度(都比线段树简短得多);

因此,所有可以用树状数组解决的问题都可以用这个“点树”来解决,另外它还有以下好处:

  • 更直观的转移(个人感受,不一定要同意);
  • 同时支持自下而上和自上而下两种方向的查找和更新,而后者树状数组不支持,所以树状数组不提供某些功能,比如说O(logN)求点集中第k小数。

posted on 2006-09-13 19:54 踏雪赤兔

转载于:https://www.cnblogs.com/MiYu/archive/2010/10/04/1842001.html

线段树的一种简化实现[转] by 踏雪赤兔相关推荐

  1. 线段树的一种简化实现[原] by 踏雪赤兔

    原文链接:http://www.cnitblog.com/cockerel/archive/2006/09/13/16806.html 相信对算法设计或者数据结构有一定了解的人对线段树都不会太陌生.它 ...

  2. 线段树入门之夜空星亮

    --------------------------------------------不是能不能办到的问题,既然我已经下定决心要成为海贼王了,如果因此而战死的话,也无所谓了. 承接上一章节,继续探索 ...

  3. 李超线段树(Li-Chao Segment Tree)

    李超线段树 李超线段树是一种用于维护平面直角坐标系内线段关系的数据结构.它常被用来处理这样一种形式的问题:给定一个平面直角坐标系,支持动态插入一条线段,询问从某一个位置 (X,+∞)(X,+\inft ...

  4. (转)线段树的区间更新

    原文地址:http://blog.csdn.net/zip_fan/article/details/46775633 写的很好,昨天刚刚开始写线段树,有些地方还不是很明白,看了这篇博文,学会了数组形式 ...

  5. 线段树segment_tree go语言实现

    线段树(segment tree) 什么是线段树 线段树是一种二叉搜索树,什么叫做二叉搜索树,首先满足二叉树,每个结点度小于等于二,即每个结点最多有两颗子树,何为搜索,我们要知道,线段树的每个结点都存 ...

  6. 线段树的数组大小下限及证明

    线段树的数组大小下限及证明 手动博客搬家: 本文发表于20170820 20:23:52, 原地址https://blog.csdn.net/suncongbo/article/details/774 ...

  7. 【学习笔记】线段树的数组大小下限及证明

    手动博客搬家: 本文发表于20170820 20:23:52, 原地址https://blog.csdn.net/suncongbo/article/details/77432667 线段树是一种将一 ...

  8. HDU - 3667 Hotel(线段树+区间合并)

    题目链接:点击查看 题目大意:给出n个连续的空房间,依次进行m个操作,操作一是查询操作,查询在总区间内的一段连续的长度为x的空房间,并 且该位置要靠左,如果查询到返回最左边的端点,并将其占用,找不到返 ...

  9. 看动画学算法之:线段树-segmentTree

    文章目录 简介 最小线段树 线段树的构建 线段树的搜索 线段树的更新 线段树的复杂度 简介 什么是线段树呢?线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树 ...

最新文章

  1. Science | 机器学习揭示了构建人造蛋白质的秘诀
  2. 简单粗暴tensorflow2.0
  3. 用combobox扩展控件(dsCtrlComboBox)做出类似QQ登录界面的效果
  4. 前端每日实战:56# 视频演示如何用纯 CSS 描述程序员的生活
  5. (王道408考研数据结构)第七章查找-第四节:哈希表(基本概念及其操作)
  6. 苹果修复今年以来的第13个0day,影响iOS 和 macOS
  7. BAT工程师自研存储引擎,火爆Github!!大家速度顶起来
  8. Objective-C内存管理
  9. PC批量转换网易ncm音乐
  10. 计算机网络信息安全保密制度,档案馆计算机网络系统和信息安全保密制度
  11. 黄教头第六周作业 一个基础的反射型xss
  12. 直流有刷伺服电机驱动器
  13. ICC学习——LAB1
  14. Long类型数据比较
  15. python爬虫读取pdf_python爬虫处理在线预览的pdf文档
  16. 小程序项目:微信小程序美容理发店预约系统app——计算机毕业设计
  17. FileZilla使用手册
  18. 局域网传输工具需求分析
  19. Rust语言——cargo、crates.io
  20. c语言weak弱化符号

热门文章

  1. 阿里云学生机:少买一个皮肤,成就你的不同凡想!
  2. 英语知识点整理day13-谚语学习(E字母开头)
  3. “自卑式备考”?这5种心态不能有!
  4. 通信原理:数字信号的载波传输
  5. 天哪!我的十一假期,被人工智能操控了
  6. linux开发工程师前景_选择成为软件开发工程师的5个原因
  7. 推荐编程电脑(个人想法)
  8. 一位父亲对儿子说的话,值得深思!
  9. 电视盒子cpu天梯图排行榜 2023电视盒子cpu对比评测
  10. mybatis choose标签的用法