线段树一点理解+模板

本篇介绍线段树的区间查询和单点修改

线段树

  今天听了lfw讲线段树(lfw讲的真心好),也试着把今天的题目做了几道(嘤嘤嘤做不动啊啊好难),对于线段树的基础应用多少有了一点点体会。

   线段树顾名思义,是一种树形的数据结构,但不一样的是,这棵树的节点代表的是一个区间,也就是说,线段树很大程度上是在解决区间的问题,跟树状数组有点意思(但我觉得线段树更好理解额)。先看下面的图:

         相当于父节点保存了子节点的情况,比如,我们要求区间最大值,[1,1] [2,2]的父节点是[1,2],那么[1,2]这个节点保存的就是子树中的最大值,当我们要查询一段区间的最大值的时候,返回这个节点保存的值就可以了。由于是树形结构,我们查询的时候自然是只能从根节点开始,也就是从最大的区间,不断缩小,一直把区间缩小到我们要求的那个,那么,每次查询,我们经过的路径最多也就是logn,情况是比较理想的。

        那么,有的同学可能会发现,如果我们查询的区间并不是某个节点怎么办呢?比如我们要查询区间[4,8],显然没有一个节点是完整的4到8,但是我们可以发现,[4,8]可以划分为区间[4,5]和[6,8],如果我们要求 [4,8]的最大值,自然就是把这两个区间的最大值再取一个max啦。

        但是问题又来了:怎么把[4,8]划分成[4,5]和[6,8]呢?换句话说,我们怎么知道划分成了哪几个呢?下面我用文字模拟一遍这个寻找过程:

         从根节点的区间[1,10]开始,可以知道,根节点的左子树的根的区间右端点是10/2=5,右子树的根的区间左端点是10/2+1=6;显然,4在左子树中,而8是在右子树中,那我们就可以知道,我们要查询的这个区间肯定是分开一部分在左子树中,另一部分在右子树中,那么我们就分别在两棵子树中找,以此类推,直到找到。

下面是板子:

树的结构体

struct node
{
     int l,r;
     int mscore;
}tree[maxn<<2];

查询

可以结合代码理解:

int query(int k,int l,int r)//从编号k开始查询区间[l,r]的最大值
{
     //printf("mm\n");
     int mm;
     if(tree[k].l==l&&tree[k].r==r)//刚好找到了代表这个区间的节点
          return tree[k].mscore;
     int mid=(tree[k].l+tree[k].r)>>1;
     if(l>=mid+1)//要找的区间左端点都在右子树,那么只需到右子树中去找
          mm=query(k<<1|1,l,r);
     else if(r<=mid)//要找的区间右端点都在左子树,只需到左子树中找
          mm=query(k<<1,l,r);
     else//否则就是我们上面说的,到左右两边都去找,最后取两边的最大值
          mm=max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
     return mm;
}

(树的数据结构,我们一般都采用递归的方法处理

总的来说,线段树可以很方便的实现对于区间的操作,比如求区间最大值啦、区间求和啦,都跟上面提到的思路差不多。

修改区间的值

         当然还有一个不容忽视的问题,当我们想要修改一个值的时候要怎么做呢?根据上面的图片我们可以看出,每个节点保存了一个区间的信息,当这个区间的某个值发生了改变,这个节点保存的信息就有可能发生变化,比如,如果节点保存的是一个区间的最大值,当我们把这个区间的某个值变大,那这个节点保存的信息就要改变。我们同样采用递归的方法来实现。

void change(int k,int d,int x)//从编号k开始把id为d的学生成绩改为x
{
     if(tree[k].l==d&&tree[k].r==d)//找到了代表这个点的叶子节点(叶子节点代表的区间只有一个值)
     {
          tree[k].mscore=x;
          return;
     }
     int mid=(tree[k].l+tree[k].r)>>1;
     if(d>=tree[k].l&&d<=mid)//在左子树
          change(k<<1,d,x);
     else              //在右子树
          change(k<<1|1,d,x);
     tree[k].mscore=max(tree[k<<1].mscore,tree[k<<1|1].mscore);
}

建树

忘记了最重要的一点:建树!即建出初始的树来支撑我们的修改和查询哇。思路也是递归

给出代码:

void build(int k,int l,int r)//以编号k为根节点建立从l到r的树
{
     tree[k].l=l;tree[k].r=r;
     if(l==r)
     {
          tree[k].mscore=a[l];
          return;
     }
     int mid=(l+r)>>1;
     build(k<<1,l,mid);build(k<<1|1,mid+1,r);
     tree[k].mscore=max(tree[k<<1].mscore,tree[k<<1|1].mscore);
     //printf("mm\n");
}

注意线段树的常数有点大,为了避免被有些题目卡常,*2、/2最好采用位运算

---------------------------------------------------------我只是个分割线哇------------------------------------------------------------------------------

下一篇是稍稍有点点麻烦的区间修改哇

呼呼

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.m或d论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 、1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值