线段树 入门详解

概念(copy度娘):

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。

通俗地讲:

线段树就是把一个线段转变为一个二叉树,如下所示:

一个线段长度为4,则把它变成线段树,就是这个样子

这样如果你想改变一个区间的值,只用O(logn)。比一般算法快了许多。

但是空间复杂度就会高一些,比如本来这个线段只占4,现在变成了7.

最基本的题目:

为了方便大家了解线段树的建树+改变+查找,我就以最基本的修改区间范围值的题做示范:

题曰:给定一个长度为L的数组,每一位的开始值都是0,然后给出n条信息,每行信息包括a,b,c。

含义是在开区间(a,b)中所有的值加上c

然后输入一个k,询问k的值。

输入:

第一行输入信息数n,数组长度L。

接下来2到n+1行输入a,b,c。

最后一行输入k

输出:

k的值

输入示例:

2 4

1 3 1

2 4 4

2

输出示例:

5

建树:

看完题后我们开始建树。

这是线段树中最简单的部分。

顺便说一下,线段树英文是:segtree

struct node
{
    int l,r,data;
}segtree[100010];//首先你要建一个线段树,l是这个点的左边(就比如上图根节点的1),r是这个点的右边,比如上图根节点的4。data就是这个点的增减标记,记录这个店增加了几
void build(int index,int left,int right)//递归实现建树
{
    if(left==right)//如果这个点是叶节点,就return;
    {
        segtree[index].r=right;
        segtree[index].l=left;
        return ;
    }
    segtree[index].l=left;//给此节点的左右边界赋值
    segtree[index].r=right;
    int mid=(left+right)/2;
    build(index*2,left,mid);//递归建立左子树和右子树
    build(index*2+1,mid+1,right);
} 

一上就是简单的建树,用到了递归,大家应该都能看懂。

增减值:

我实在不会术语,就这样吧。下面来教大家怎样改变线段树的值。

想要改变线段树的值,不是直接改变,因为线段树上只有一个l一个r没有表示实际的值。

这时候我们就要创建一个data,来标记这个线段树的增减。

比如我们要使2~4区间加1,可以这样

从根节点1~4区间开始搜索,发现它的左右子节点(1~2、3~4)都有2~4区间,所以搜索两边。

先搜索左子节点,发下这个节点的左节点(1~1)没有2~4,于是不搜索,接着搜索右节点(2~2),发现此节点被完全包括在了2~4,因此义不容辞地将这个点标记从原本的0加上一个1,并且断绝此节点搜索。

我们回到最开始的右节点,(3~4),发现这个节点又被完全包括在2~4里面于是标记从零到一,然后结束搜索。

一番搜索过后,线段树,也就是segtree[].data标记如下:

之后用这个来如何处理,我稍后会讲

现呈上代码(编译器坏了,手打的,难免会有一些bug,见谅)

void update(int index,int left,int right,int c)//还是递归标记
{
    if(segtree[index].l>=left && segtree[index].r<=right)//如果全都被包括,就直接加上去
   {
        segtree[index].data+=c;
        return ;
   }
   int mid=(segtree[index].l+segtree[index].r)/2;
   if(mid>=left)//分别判断是否包含一部分
        update(index*2,left,right,c);
   if(mid<right)
       update(index*2+1,left,right,c);
}

查询:

最激动人心的时刻到了,查询!!!其实很简单,就是从根节点一直走到你要查询的叶子节点,一路上都加上segtree[].data就好了。

上面的图,你查询3,根节点+0,往右边走+1,再往左边走+0,于是结果就是1.

代码如下:

void search(int index,int k,int ans)
{
    int left=segtree[index].l;
    int right=segtree[inrdex].r;
    if(l==k && r==k)
    {
        cout<<ans;
        return ;
    }
    int mid=(left+right)/2;
    if(k<=mid)
        search(index*2,k,ans+segtree[index].data);
    if(k>mid)
        search(index*2+1,k,ans+segtree[index].data);
}

好了,不知道完整代码还要不要,应该不要了吧。

开始build(1,1,L);

就是没读入一条信息,a,b,c然后调用update(1,a,b,c);

最后输入k调用search(1,k,0)

口胡完毕,没听懂评论就好。

时间: 2024-08-06 00:51:01

线段树 入门详解的相关文章

线段树数据结构详解

线段树数据结构详解 Coded by Jelly_Goat. All rights reserved. 这一部分是线段树. 线段树,顾名思义,是一种树形数据结构,适用于各种求区间统一算法的动静两平衡的数据结构. 这里什么是统一算法?(自己口胡的统一算法) 比如求最大值or最小值.区间求和,一样的区间都是一样的算法,这也是和动态dp不同的地方. 前置知识1:二叉搜索树 二叉搜索树就是根节点比左儿子大,比右儿子小的一种二叉树. 前置知识2:向量存储 向量存储是用来存完全二叉树儿子和父亲关系的. 如果

主席树入门详解+题目推荐

主席树学名可持久化线段树,就是这个可持久化,衍生了多少数据结构 为什么会有主席树这个数据结构呢?它被发明是用来解决什么问题的呢? 给定n个数,m个操作,操作类型有在某个历史版本下单点修改,输出某个历史版本下某个位置的值的值,n和m小于等于1e6 乍一看是不是一点头绪也没有.我们先来想想暴力怎么做,暴力存储第i个状态下每个数的值,显然这样做不是TLE就是MLE,我们不妨管这种状态叫做TM双LE. 如果没有这个历史状态显然处理很简单,一个线段树就解决了.那么加上历史状态呢?如果我们优化一下暴力,我们

Linq之旅:Linq入门详解(Linq to Objects)

示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集成查询).通过LINQ,我们可以使用相同API操作不同的数据源.接下来就让我们看看LINQ是什么以及如何使用? 再此之前,需要先了解的相关技术 1. 隐式类型.匿名类型.对象初始化器 1) 隐式类型,使用var关键字创建,C#编译器会根据用于初始化局部变量的初始值推断出变量的数据类型.(不过我个人认

线段树入门小结

QUE:线段树? 称谓: 从刘汝佳的书中得知,"这种数据结构在学术界没有统一的术语,但线段树是最常见的叫法.其他叫法包括区间树(interval tree).范围树(range tree)等,但这些属于在特定的场合(如计算几何)中有着特殊的意义".怎么叫看读者的心情,以下统一用线段树称呼. 先来作一些了解: 线段树是一棵二叉树,它的左右儿子也都是一棵线段树.(定义) 线段树也叫区间树,为什么叫它区间树呢?因为线段树是一种基于区间的数据结构. 线段树的每个节点代表一个区间 [L,R],其

线段树入门(Billboard)

Billboard Time Limit:8000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description At the entrance to the university, there is a huge rectangular billboard of size h*w (h is its height and w is its width). The board is the place where

【转】Asp.Net MVC3 简单入门详解过滤器Filter

原文地址:http://www.cnblogs.com/boruipower/archive/2012/11/18/2775924.html 前言 在开发大项目的时候总会有相关的AOP面向切面编程的组件,而MVC(特指:Asp.Net MVC,以下皆同)项目中不想让MVC开发人员去关心和写类似身份验证,日志,异常,行为截取等这部分重复的代码,那我们可以通过AOP截取实现,而在MVC项目中我们就可以直接使用它提供的Filter的特性帮我们解决,不用自己实现复杂的AOP了. 在Asp.net Mvc

线段树入门(I Hate It)

I Hate It Time Limit:3000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老师有时候需要更新某位同学的成绩. Input 本题目包含多组测试,请处理到文件结束. 在每个测试的第一行,

webpack入门详解

webpack入门详解(基于webpack 3.5.4  2017-8-22) webpack常用命令: webpack --display-error-details    //执行打包 webpack -w               // 提供watch方法:实时进行打包更新 webpack -p           // 对打包后的文件进行压缩 webpack -d            // 提供source map,方便调式代码 webpack -dev-server --open 

《数据结构》线段树入门(二)

今天继续介绍——线段树之延迟标记 接上期<数据结构>线段树入门(一):http://www.cnblogs.com/shadowland/p/5870339.html 在上期介绍了线段树的最基本内容(线段树单点修改,区间查询),这次将介绍:区间修改,区间查询. Question: 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和. 输入描述: 第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,每行表示操作的个数,如果第一数是1,后接3个正