线段树(区间树)

1.基本概念

线段树,Segment tree,是一颗二叉树,树的每个节点代表一个区间[a,b]。故又叫做区间树,Interval tree。

用于解决线段的并,或区间覆盖问题。

性质:线段树是平衡二叉树,最大深度为logN(N为线段树所表示区间的长度)。

2.线段树API

存储结构:

public class Node
{
    public int left;
    public int right;
    public int value;
    public Node leftChild;
    public Node rightChild;
}

l BuildTree(a,b)

建一棵从a到b的空线段树;

Node BuildTree(int a, int b)
{
    Node node = new Node();
    node.left = a;
    node.right = b;
    node.value = 0;
    if (a == b) return node;
    node.leftChild = BuildTree(a, (a + b) / 2);
    node.rightChild = BuildTree((a + b) / 2, b);
    return node;
}

l Insert(T,c,d,value)

将区间[c,d]插入线段树T中;

并维护节点信息value

void Insert(Node p, int c, int d, int key)
{
    if (c <= p.left && p.right <= d)
    {
        p.value = key;
        return;
    }

    if (c <= (p.left + p.right) / 2)
    {
        Insert(p.leftChild, c, d, key);
    }
    if (d > (p.left + p.right) / 2)
    {
        Insert(p.rightChild, c, d, key);
    }
}

l Delete(T,c,d,value)

将区间[c,d从线段树T中删除;

并维护节点信息value

void Delete(Node p, int c, int d)
{
    if (c <= p.left && p.right <= d)
    {
        p.value = 0;
        return;
    }

    if (c <= (p.left + p.right) / 2)
    {
        Delete(p.leftChild, c, d);
    }
    if (d > (p.left + p.right) / 2)
    {
        Delete(p.rightChild, c, d);
    }
}

l Search(T,c,d)

从T中查找[c,d]的节点信息

int Search(Node p, int a, int b)
{
    int ans = 0;
    if (a <= p.left && p.right <= b)
    {
        ans = p.value;
        return ans;
    }

    if (a <= (p.left + p.right) / 2)
    {
        ans = Search(p.leftChild, a, b);
    }
    if (b > (p.left + p.right) / 2)
    {
        ans = Search(p.rightChild, a, b);
    }

    return ans;
}

l TreeLength(T)

计算T的测度,即线段树的覆盖程度

int QLen(Node p)
{
    if (p.value > 0)
    {
        return p.right - p.left;
    }
    else if (p.right - p.left == 0) return 0;
    else
        return QLen(p.leftChild) + QLen(p.rightChild);
}

3.离散化思想

离散化:离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。

参考百度百科

线段离散化方法:先对起点进行排序,然后计算区间覆盖

时间: 2024-12-22 06:23:07

线段树(区间树)的相关文章

算法导论--动态顺序统计与区间树

本文的基础是红黑树 算法导论–红黑树 通过在基础的数据结构中添加一些附加信息,来扩张一种标准的数据结构,然后编写新的操作来支持所需要的应用.下面是介绍在红黑树的基础上扩张的数据结构. 1.动态顺序统计 动态顺序统计可以在O(lgn)时间内确定任何的顺序统计量(即在n个元素的集合中,能在O(lgn)的时间内确定第i小的元素),同时也可以在O(lgn)的时间内计算一个元素的秩(即它在中序遍历下的位置顺序). 1 添加附加信息 结点x中加入x.size , size的大小为以x为根的子树(包含x本身)

HDU 1689 Just a Hook 线段树区间更新求和

点击打开链接 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18894    Accepted Submission(s): 9483 Problem Description In the game of DotA, Pudge's meat hook is actually the most horrible

HDU 3911 Black And White(线段树区间合并)

Problem Description There are a bunch of stones on the beach; Stone color is white or black. Little Sheep has a magic brush, she can change the color of a continuous stone, black to white, white to black. Little Sheep like black very much, so she wan

HDU4027 Can you answer these queries 线段树区间求和+剪枝

给了你n,然后n个数字在一个数组中,接下来m个询问,每个询问三个数字 t,x,y,若t==0,那么修改区间[x,y]的每一个值,变为原来每个位置上的数 开根号取整,若t==1,那么对区间[x,y]求和 由于n,m,很大,所以树状数组铁定超时,若直接用线段树来做区间修改,那么也是超时,这类题目没别的方法了,静心剪枝,发现题目给的数据范围为2^63,有没有发现,2^63开根号 绝对不需要开10次,就能到1,到1以后就不需要再开了,意思就是若有某个区间[x,y]每一个点的值都为1时,这一段区间事实上是

POJ 3667 线段树区间合并

http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html 用线段树,首先要定义好线段树的节点信息,一般看到一个问题,很难很快能确定线段树要记录的信息做线段树不能为了做题而做,首先线段树是一种辅助结构,它是为问题而生的,因而必须具体问题具体分析回忆一下RMQ问题,其实解决RMQ有很多方法,根本不需要用到线段树,用线段树解决RMQ,其实是利用线段树的性质来辅助解决这个问题回忆一下求矩形面积并或周长并的问题,一般使用的是扫描

HDU 3308 LCIS (线段树区间合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[mid + 1] > a[mid],写的细心点就好了. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int MAXN = 1

POJ 2528 Mayor&#39;s posters (线段树区间更新+离散化)

题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值.由于l和r范围比较大,内存就不够了,所以就用离散化的技巧 比如将1 4化为1 2,范围缩小,但是不影响答案. 写了这题之后对区间更新的理解有点加深了,重点在覆盖的理解(更新左右两个孩子节点,然后值清空),还是要多做做题目. 1 #include <iostream> 2 #include <

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

HDU 5023 A Corrupt Mayor&#39;s Performance Art 线段树区间更新+状态压缩

Link:  http://acm.hdu.edu.cn/showproblem.php?pid=5023 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <string> 7 #include <cmath> 8 using namesp

HDU 5316 Magician(线段树区间合并入门)

本文纯属原创,转载请注明出处谢谢.http://blog.csdn.net/zip_fan. 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5316 Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Fantasy magicians usually gain their ability