首页 > 其他分享 >线段树入门

线段树入门

时间:2022-11-20 20:57:52浏览次数:59  
标签:lazy right 入门 int 线段 区间 节点 left

线段树是个好东西,首先要知道这些点:

1.线段树适用于任何区间修改和区间查询的操作,复杂度只有 O(logn) 贼快

2.线段树没有树状数组好写呢,其实也不难

3.线段树每一个点是管理一个区间!!

4.线段树不是所有节点都代表原数组的一个值,他可能会代表一个区间段中你想要的值

基础理论

首先上一个图

线段树

简单了解一下线段树

发现每一个节点的管理区间就是左右子所管理的区间相加

再看下一张图

将节点按照层序遍历编好号,发现:

一个节点的左孩子是它的编号的两倍,它的右孩子的编号是它的两倍加一

叶子节点管理的区间就只有它自己


深入学习

开始考虑修改

如果你使用前缀和去完成线段树的题目线段树模板1的话,你会发现:我c,还有修改!还特么是区间修改

然后你会愉快地 TLE 然后放弃并失去信心

下面就需要线段树了

线段树进行单点修改时,其他子树上的节点根本就不用动!改它干嘛!

例如,你要改原数组中的第6个↓

那么你只用去改变节点 18、12、6、3、1 的区间和的值不就完了!什么4、5、10、11,一点关系都没有!

区间更改也能解决,不过需要一些其他的东西。

实现

首先看一看如何建树!

本文只介绍静态建点、递归建树!

先定义一个结构体:

struct st
{
	int s;
	int l,r;
   	int lazy;
};

这个结构体就是一个节点!

l 和 r 分别代表这个节点管理的区间的左端点与右端点

s 是指它这个节点所管理的区间的和是多少

建树部分:

void buildtree(int i,int left,int right)
{
	t[i].l=left;
	t[i].r=right;
	if(left==right)
	{
		t[i].s=a[left];
		return ;
	}
	int mid=(left+right)/2;
	buildtree(lson,left,mid);
	buildtree(rson,mid+1,right);
	t[i].s=t[lson].s+t[rson].s;
}

首先:

参数left和right代表即将建树的部分

i代表你已经到的节点编号

接下来就可以快乐的把节点 i 的 l 和 r 赋值为 left 和 right了

如果i为叶子结点,也就是left==right时,直接把它的区间和赋值为a[left]

为什么是a[left]呢?

因为到了叶子结点,他所管理的就是他自己

算了,还是来张图吧:

比如说你要建第11个节点

看他的 l 和 r

发现都为5

所以直接赋值吧!毕竟它就是管理数组中下标为5的数

然后继续往下建树

根据上面的那张图可以发现:

他的左儿子管理的区间是 l 到 (l + r) / 2 ,右儿子是 (l+r)/2+1 到 r

所以向下建树吧

最后一步将左儿子的区间和加上右儿子的区间和就好了!

单点修改

在这里只阐述原理,不放出代码

先找到一个数

比如说第5个数:

更改以后也会更改的点有:5 2 1

所以只用把这些节点更改就完了

找到这个节点,再往根节点上去,将路途中的所有节点pushup一遍就完了

区间修改!!重中之重

讲区间修改之前,先简单讲讲懒惰标记

懒惰标记

懒惰标记是一个很好的东西,它好就好在可以降低区间修改的复杂度

具体是怎么用,是什么,接着看:


比如说我要修改区间26(居然一直在用一个图,我真勤奋~)

我都懒得上图了,直接翻翻上面的

我们会发现第9,5,18个节点会被覆盖

再看一眼结构体:

struct st
{
	int s;
	int left;
	int right;
	int lazy;
}t[maxn*4];

有没有好奇那个lazy是干什么用的

那个lazy就是懒惰标记

当你发现当前节点所管理的区间已被需要修改的区间覆盖

立即停止,将懒惰标记加上你所需要增加的值,再把这个节点所管理的区间和更新一下,然后回溯

代码:

void pushdown(int i)
{
	if(t[i].lazy==0) return; 不需要更新
	if(t[i].left==t[i].right)
	{
		t[i].lazy=0; 已经到了叶子节点,结束。因为已经改过了,下面也没有左儿子或右儿子了
		return ;
	}
	t[lson].s+=(t[lson].right-t[lson].left+1)*t[i].lazy;将左子更改
	t[lson].lazy+=t[i].lazy;懒惰标记继承给左子,为了以后将左子的左子和右子pushdown更新
	t[rson].s+=(t[rson].right-t[rson].left+1)*t[i].lazy;同理
	t[rson].lazy+=t[i].lazy;
	t[i].lazy=0;
}
void change(int i,int left,int right,int d) d为需要加上的数值
{
	pushdown(i);
	if(t[i].left==left && t[i].right==right)
	{
		t[i].lazy=d;
		t[i].s+=(right-left+1)*d;所需要加上的和为:数量*需要加上的数值
		return ;
	}
	t[i].s+=(right-left+1)*d;
	if(t[lson].right>=right) change(lson,left,right,d);判断左子或右子是否有一部分被需要更改的区间覆盖
	else if(t[rson].left<=left) change(rson,left,right,d);
	else change(lson,left,t[lson].right,d),change(rson,t[rson].left,right,d);
}

如果你要用到i这个节点,你需要先pushdown一下,因为它的左儿子和右儿子都没有更新,所以需要先pushdown更新一下

区间更改 完结撒花★,°:.☆( ̄▽ ̄)/$:.°★

单点查询

与单点更改差不多,自己想一想吧(懒得写了 比较简单)

区间查询

最后一个重点

还是看以前的图吧 ε=ε=ε=┏(゜ロ゜;)┛

接下来查询区间2~6

还是上一张图吧:

需要查询节点17,9,5,18的值

然后向上传递和

代码:

int query(int i,int l,int r)
{
	pushdown(i);
	if(t[i].left>=l&&t[i].right<=r)
		return t[i].s;
	int e=0;
	if(t[lson].right>=left)判断左子是否有覆盖部分 
		e+=quert(lson,l,r);有就加上 
	if(t[rson].left<=right)判断右子是否有覆盖部分 
		e+=query(rson,l,r);有就加上 
	return e;上传 
}

题目:

简单线段树

全部完结撒瓜!!

题目解析我会再写一篇blog

标签:lazy,right,入门,int,线段,区间,节点,left
From: https://www.cnblogs.com/Y2y7m/p/16909475.html

相关文章

  • javascript入门
    javascript入门1.javascript的介绍JavaScript一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部......
  • Linux性能工具-bpftrace入门
    一、bpftrace简介bpftrace是基于ebpf内核vm扩展出来的trace工具。bpftrace是Linux高级追踪工具和语言。该工具基于eBPF和BBC实现了通过探针机制采集内核和程序运......
  • ctfshow web入门部分题目 (更新中)
    CTFSHOW(WEB)web入门给她1参考文档https://blog.csdn.net/weixin_51412071/article/details/124270277查看链接sql注入<?php$pass=sprintf("andpass='%s'",addsla......
  • StarRocks入门
    StarRocks入门第1章StarRocks简介1.1StarRocks介绍StarRocks是新一代极速全场景MPP数据库StraRocks充分吸收关系型OLAP数据库和分布式存储系统在大数据时代的优秀研......
  • Canal 安装与入门
    MySQLBinlog简介MySQL主从复制过程1)Master主库将改变记录,写到二进制日志(BinaryLog)中;2)Slave从库向MySQLMaster发送dump协议,将Master主库的binarylogevents......
  • 篇(16)-Asp.Net Core入门实战-权限管理之用户创建与关联角色(ViewModel再用与模型验证
    入门实战-权限管理之用户创建与关联角色(ViewModel再用与模型验证二)(1).在用户管理着模块中,相比较菜单功能的代码还是比较多的,设计到用户的创建,修改,角色变更和密码重置,同时......
  • Mybatis 入门实战(2)--简单使用
    本文主要介绍Mybatis的实际使用,相关的环境及软件信息如下:Mybatis3.5.11。1、工程整体结构这里使用Maven来构建样例工程,工程目录结构如下:2、引入依赖<dependency......
  • Linux基础入门
    Linux基础入门1.Linux基础概念1.1用户类型root用户一个特殊的管理帐户,也被称为超级用户root已接近完整的系统控制对系统损害几乎有无限的能力除非必要,不要登......
  • QT入门之创建新窗口
    1.在QT里面新建1个工程,命名01QT,先生成个空的项目。 2 新建1个源文件C++Source文件,命名main.cpp.main 方法里面这样写//主应用程序QApplicationapp(argc,argv);......
  • CTF模板注入入门学习
    对于知识框架的了解,站在巨人的肩膀梭哈大佬文章,很全很nice:https://blog.csdn.net/LYJ20010728/article/details/120205725?ops_request_misc=%257B%2522request%255Fid%25......