线段树学习(一)

原创 2012年03月29日 16:26:29

先从书上把定义抄下来:

一棵二叉树,记为 T (a,b),参数 a,b表示该节点表示区间[a,b)。区间的长度b-a 记为 L。

递归定义 T[a,b]: 

若 L>1 :[a, (a+b)/2]为 T 的左儿子,[(a+b) /2,b]为 T 的右儿子。 

若 L=1 :T 为一个叶子节点。

区间[1, 10]的线段树表示方法如下: 


这里需要注意一点,图中一共有9个叶子节点,也就是说,这棵树只能代表9个点的数据,也就是[1,9]区间的数据。

所以,我们在对待线段树区间的时候,可以理解为[a,b),即左闭右开。这样,它的叶子节点也就只代表一个点a。

首先,线段树是一个完全二叉树。它有以下性质:

具有n个结点的完全二叉树的深度为[log(2)n]+1([ ]表示取上整)

根据线段树是完全二叉树的这一性质,我们可以用数组保存结点,当然,结点中可以根据需要加些不同的值用来保存不同的信息。

const int Max=pow(2,ceil(log2(Max_N))+1)	//数组最大值计算方法

每个结点的左右孩子可以直接用数组下标去找,左孩子是2*x,右孩子是2*x+1,父亲是x/2。(按照满二叉树运算,虽然浪费一些空间,但可以提高效率)

强大的位运算:

#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)

线段树构造:

struct Tnode
{
    int l,r;                    //l,r表示此结点所代表区间的左右端点
    /*?*/                      //结构体里面还可以加东西,这里没有加
}node[Max];
void Build(int t,int l,int r)   //t表示数组下标,l、r表示区间左右端点
{
    node[t].l = l , node[t].r = r;//记录此结点所代表区间的左右端点
    if(l == r-1)        //已到叶子结点,不再向下递归建树
    {
        return ;
    }
    int mid = MID(l,r); //将区间分成两半
    Build(L(t),l,mid);  //建立此结点的左孩子
    Build(R(t),mid,r);  //建立此结点的右孩子
}

线段树查询:

void Query(int t,int l,int r)   //t表示数组下标,l、r表示待查询区间左右端点
{
    if( node[t].l == l && node[t].r == r )//已经找到区间
    {
        return ;
    }
    int mid = MID(node[t].l,node[t].r);
    if(l >= mid)                //如果左端点大于mid,待查询区间一定在右孩子中。
        Query(R(t),l,r);
    else
        if(r <= mid)            //如果右端点小于mid,待查询区间一定在左孩子中。
            Query(L(t),l,r);
        else                    //如果不满足上述情况,将待查询区间分割成[l,mid)和[mid,r)继续查找
        {
            Query(L(t),l,mid);
            Query(R(t),mid,r);
        }
}

好了,先写这么多吧。欢迎大家批评指正。

HDU 1542 Atlantis(线段树:扫描线)

HDU1542 Atlantis(线段树:扫描线) 题意: 二维平面有n个平行于坐标轴的矩形,现在要求出这些矩形的总面积. 重叠部分只能算一次. 分析:        首先假设有下图两个矩阵,我们如果...
  • u013480600
  • u013480600
  • 2014年03月30日 01:46
  • 3218

线段树经典类型归纳

HDU 1754 单点更新,区间查询最大值,水题…… #include #include #include #include #include #include #include #include #...
  • u011466175
  • u011466175
  • 2014年07月30日 10:27
  • 1009

【理解】线段树——扫描线

原文:http://www.cnblogs.com/kane0526/archive/2013/02/26/2934214.html 题目大意: 给你n个矩形,求他们的总面积之和。 解题思路:...
  • otowa
  • otowa
  • 2016年02月19日 07:56
  • 1135

线段树学习心得 poj3468

线段树学习心得分享,附加poj题目一道。
  • bright_light_in_dark
  • bright_light_in_dark
  • 2016年05月22日 10:51
  • 353

线段树难题--史上最大值nkoj3726

P3726史上最大值 时间限制 : - MS   空间限制 : 165536 KB   问题描述 给出一个长度为n的序列,一开始序列中每个数字都为0。现在有两种操作: 1.将区间[x,y]的数...
  • INCINCIBLE
  • INCINCIBLE
  • 2016年07月21日 20:48
  • 420

[CodeVS 4927] 线段树练习5:两个Lazy Tag的线段树

题意:维护一个长为n(n
  • ruoruo_cheng
  • ruoruo_cheng
  • 2016年11月13日 17:45
  • 312

线段树学习记录

学完了自己半残不残的Tarjan算法,为于机房同步,我开始学习线段树。。。。。。 先给出线段树定义: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一...
  • Lcomyn
  • Lcomyn
  • 2014年11月05日 13:52
  • 1142

C++ 线段树—模板&总结

在信息学竞赛中,经常遇到这样一类问题:这类问题通常可以建模成数轴上的问题或是数列的问题,具体的操作一般是每次对数轴上的一个区间或是数列中的连续若干个数进行一种相同的处理。常规的做法一般依托于线性表这种...
  • txl16211
  • txl16211
  • 2015年04月29日 23:15
  • 2832

线段树从零开始

从零开始讲线段树,适合有一定C/C++编程基础,想学习线段树的读者。
  • u012891242
  • u012891242
  • 2016年08月22日 22:26
  • 5178

线段树经典操作模板(单点更新,替换;区间更新,替换;区间求和求最值)

对于线段树的讲解此篇不再赘述,下面列出线段树应用中最常用的几种操作的代码。(具体题目未贴出,仅供有一定基础者参考代码风格) 另外,注意多组输入要写scanf("%d%d",&n,&m)!=EOF,线...
  • NK_test
  • NK_test
  • 2015年08月09日 18:37
  • 1302
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:线段树学习(一)
举报原因:
原因补充:

(最多只允许输入30个字)