线段树的一种简化实现[原] by 踏雪赤兔
原文链接: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;
}
P.S.:
在写完这篇文章一段时间后,我认识了另一种功能上比较类似的数据结构,叫做“树状数组”。它们有不少相似之处:
- 针对点集的处理(添加、删除、查找);
- 相似的时空复杂度(logN时间,2N空间);
- 相似的编程复杂度(都比线段树简短得多);
因此,所有可以用树状数组解决的问题都可以用这个“点树”来解决,另外它还有以下好处:
- 更直观的转移(个人感受,不一定要同意);
- 同时支持自下而上和自上而下两种方向的查找和更新,而后者树状数组不支持,所以树状数组不提供某些功能,比如说O(logN)求点集中第k小数。
转载于:https://www.cnblogs.com/yewei/archive/2012/05/05/2484528.html
线段树的一种简化实现[原] by 踏雪赤兔相关推荐
- 线段树的一种简化实现[转] by 踏雪赤兔
转载自 http://www.cnitblog.com/cockerel/archive/2006/09/13/16806.html 相信对算法设计或者数据结构有一定了解的人对线段树都不会太陌生.它是 ...
- 李超线段树(Li-Chao Segment Tree)
李超线段树 李超线段树是一种用于维护平面直角坐标系内线段关系的数据结构.它常被用来处理这样一种形式的问题:给定一个平面直角坐标系,支持动态插入一条线段,询问从某一个位置 (X,+∞)(X,+\inft ...
- 线段树segment_tree go语言实现
线段树(segment tree) 什么是线段树 线段树是一种二叉搜索树,什么叫做二叉搜索树,首先满足二叉树,每个结点度小于等于二,即每个结点最多有两颗子树,何为搜索,我们要知道,线段树的每个结点都存 ...
- 线段树的数组大小下限及证明
线段树的数组大小下限及证明 手动博客搬家: 本文发表于20170820 20:23:52, 原地址https://blog.csdn.net/suncongbo/article/details/774 ...
- 【学习笔记】线段树的数组大小下限及证明
手动博客搬家: 本文发表于20170820 20:23:52, 原地址https://blog.csdn.net/suncongbo/article/details/77432667 线段树是一种将一 ...
- 数据结构 —— 线段树
[概述] 线段树是一种二叉搜索树,其存储的是一个区间的信息,每个结点以结构体的形式去存储,每个结构体包含三个元素:区间左端点.区间有端点.该区间要维护的信息(视实际情况而定),其基本思想是分治的思想. ...
- 线段树入门之夜空星亮
--------------------------------------------不是能不能办到的问题,既然我已经下定决心要成为海贼王了,如果因此而战死的话,也无所谓了. 承接上一章节,继续探索 ...
- 树状数组及线段树入门(SDNU1665-1668)
目录 前言 树状数组 先导 单点修改区间查询 区间修改区间查询 线段树 先导 单点修改区间查询--递归形式 单点修改区间查询--非递归形式 区间修改区间查询--递归形式 区间修改区间查询--非递归形式 ...
- 炸鸡块君与FIFA22 线段树(牛客)
原题链接:登录-专业IT笔试面试备考平台_牛客网 维护一个线段树的三种不同状态 树的大小是点数的4倍,记得数组要开四倍 AC代码: #include<bits/stdc++.h> us ...
最新文章
- python的redis数据库连接与使用
- SQL2K数据库开发二之查看和修改Sample数据库
- 如何查看方法在哪里被调用
- python【数据结构与算法】程序设计:划分整数(DP)
- GDCM:dicom文件固定方向的测试程序
- s:selected的用法
- Mac OS X 10.10.3对SSD开启Trim功能
- linux配置apache服务器项目文档,Apache(Linux)服务器配置文档.doc
- at指令代码 stm32f030_stm32+ESP8266AT指令详细说明
- swift 拖动按钮_Swift 简单控件示例:滑块(UISlider)
- java视频编辑怎么实现_OpenGL 实现视频编辑中的转场效果
- 统计叶子结点c语言,统计二叉树中叶子结点个数
- 经纬度(度分秒)坐标转换为小数格式(weixin公众号【图说GIS】)
- Indented Inventory BOM如何转为最终的单层采购BOM
- 快去抢票!今天开始!2020元旦春节火车票购票日程攻略来了
- CRT团队组员博客地址统计
- linux系统php安装sockets扩展
- MC皮肤站和外置登陆教程
- 前后端分离vue2+node易购商城后台管理系统
- Android应用接入微信开放平台
热门文章
- 技术人员如何创业《二》- 合伙人的模式
- alertdialog 自定义样式回调选手_日志MIUI 10 9.8.7 内测更新资讯 小米8自定义水印...
- DaVinci:Camera Raw(ARRI)
- vegfr2药物|适应症|市场销售数据-上市药品前景分析
- 战地5离线bot模式_战地2怎么和局域网玩家一同打电脑BOT
- Word Formation
- python使用serial模块,通过串口控制云台(基于PELCO-D协议)
- Excel学习笔记5||日期时间函数NOW、DATE、DATEDIF、WEEKDAY... ...
- 3.4nbsp;企业家——3.4.1nbsp;史蒂…
- chrome设置:新标签页打开指定网页