树状数组与线段树<2>——线段树初步

这个系列终于更新了(主要因为树状数组初步比较成功)

话不多说,切入正题。

什么是线段树?

线段树是一种支持单点修改区间查询(树状数组也行) and 区间修改单点查询(树状数组不行) and 区间修改区间查询(树状数组更不行)的高级数据结构,相当于树状数组plus版。

——该图片来自百度百科

建树

我们先来看看怎么建树。线段树其实就是一个二叉树,每个人结点管辖一个区间。所以,我们开始可以建树了。左孩子有孩子分别递归一下,tree_{i}.sum=tree_{i*2}.sum+tree_{i*2+1}.sum

void build(int idx,int l,int r){
    tree[idx].l=l;
	tree[idx].r=r;
    if(l==r){//如果这个节点是叶子节点
        tree[i].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(idx*2,l,mid);//分别构造左子树和右子树
    build(idx*2+1,mid+1,r);
    tree[idx].sum=tree[idx*2].sum+tree[idx*2+1].sum;
}

顺便多一嘴,线段树一般开4倍空间(除非你动态开点),但下面也有提及。

单点修改 区间查询

→单点修改

这个不难,直接向下递归就完事儿了。返回时按tree_{i}.sum=tree_{i*2}.sum+tree_{i*2+1}.sum做就可以了。

void modify(int idx,int k,int x){
    if(tree[idx].l==tree[idx].r){//找到了
        tree[idx].sum+=x;
        return;
    }
    if(k<=tree[idx*2].r)
		modify(idx*2,k,x);
    else
		modify(idx*2+1,k,x);
    tree[idx].sum=tree[idx*2].sum+tree[idx*2+1].sum;//返回更新
    return;
}

→区间查询

接下来我们看看如何区间查询。我们其实就找我们来看看哪些区间被目标区间包含了。所以,从根节点开始往下递归,如果当前结点是被要查询的区间包含了,则返回这个结点的信息,时间复杂度为\Theta (logn)

int query(int idx,int l,int r){
    if(tree[i].l>=l && tree[i].r<=r)//如果区间被包括在目标区间里面,直接返回
        return tree[i].sum;
    if(tree[i].r<l || tree[i].l>r)//八竿子打不着
        return 0;
    int res=0;
    if(tree[idx*2].r>=l)
        res+=query(idx*2,l,r);//左端点和目标区间有交集,搜左子树
    if(tree[idx*2+1].l<=r)
        res+=query(idx*2+1,l,r);//搜右子树
    return res;
}

区间修改 单点查询

区间修改的话,就把这个区间加上一个k的标记 ,单点查询的时候,就从上跑到下,把沿路的标记加起来就好。

→区间修改

void modify(int idx,int l,int r,int k) {
	if(tree[idx].l>=l && tree[idx].r<=r){
		tree[idx].tag+=k;
		return;
	}
	int mid=(tree[idx].l+tree[idx].r)>>1;
	if(l<=mid)
		modify(idx*2,l,r,k);
	if(r>mid)
		modify(idx*2+1,l,r,k);
}

→单点查询

void query(int pos,int x){
	int res+=tree[pos].tag;
	if(tree[pos].l==tree[pos].r)
		return res;
	int mid=(tree[pos].l+tree[pos].r)>>1;
	if(x<=mid)
		query(pos<<1,x);
	else	
		query(pos<<1|1,x); 
}

到这,你就可以去做洛谷P3368了。今天元宵节,我就不给你们挖坑了(其实是懒)。

#include <bits/stdc++.h>
using namespace std;
const int maxn=500005;
int ans;
int a[maxn];	
struct node{
	int l,r;
	int num;
}tr[maxn*4];//线段树开四倍空间 
void build(int p,int l,int r){
	tr[p]={l,r,0};
	if(l==r){
		tr[p].num=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
}	
void modify(int p,int l,int r,int k){
	if(tr[p].l>=l && tr[p].r<=r){
		tr[p].num+=k;
		return;
	}
	int mid=(tr[p].l+tr[p].r)>>1;
	if(l<=mid)
		modify(p<<1,l,r,k);
	if(r>mid)
		modify(p<<1|1,l,r,k);
}
void query(int p,int x){
	ans+=tr[p].num;
	if(tr[p].l==tr[p].r)
		return;
	int mid=(tr[p].l+tr[p].r)>>1;
	if(x<=mid)
		query(p<<1,x);
	else
		query(p<<1|1,x); 
}
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	    cin>>a[i];
	build(1,1,n);
    for(int i=1;i<=m;i++){
        int op;
        cin>>op;
        if(op==1){
            int x,y,k;
            cin>>x>>y>>k;
            modify(1,x,y,k);
        }
        else{
            ans=0;
            int x;
            cin>>x;
            query(1,x);
            cout<<ans<<endl;
        }
    }
	return 0
}

还是没忍住,挖了一个坑,你们自己找吧ψ(`∇´)ψ

区间查询 区间修改(懒标记lazy tag)

读完这个,你才能说你会线段树。

当然,这个可以说是最难的一个part了。你可能会说把前面的代码直接拉来用不就结束了吗,但用不了多久你就会发现这个想法非常"智慧"。

那老办法行不通了,有什么新办法吗?当然有!它就是懒标记。懒标记是怎么个回事呢?还是刚刚

那张图。

比如我们要给[1,5]每一个加一,那么向下递归时,可以先不直接操作,而是将管辖那个区间的"领导"的值加上1*5。当然递归回去的时候不要忘记更新上面的结点。(不要问我为什么一定要这么干,因为我也不知道)

先看一下修改的代码。

void modify(int idx,int l,int r,int k){
    if(tree[idx].r<=r && tree[idx].l>=l){
        tree[idx].sum+=k*(tree[idx].r-tree[idx].l+1);
        tree[idx].lazy+=k;//记录lazytag
        return;
    }
    push_down(idx);//向下传递
    if(tree[idx*2].r>=l)
        modify(idx*2,l,r,k);
    if(tree[idx*2+1].l<=r)
        modify(idx*2+1,l,r,k);
    tree[idx].sum=tree[idx*2].sum+tree[idx*2+1].sum;
    return;
}

这个是push_down的代码↓

void push_down(int idx){//清空lazytag 
    if(tree[idx].lazy!=0){
        tree[idx*2].lazy+=tree[idx].lazy;
        tree[idx*2+1].lazy+=tree[idx].lazy;
        int mid=(tree[idx].l+tree[idx].r)/2;
        tree[idx*2].sum+=tree[idx].lazy*(mid-tree[idx*2].l+1);
        tree[idx*2+1].sum+=tree[idx].lazy*(tree[idx*2+1].r-mid);
        tree[idx].lazy=0;//归零
    }
    return;
}

那查询呢?一样。只要没有被完全包含在目标区间里就push_down,下放懒标记。并让每个区间加上(r-l) \times lazy

int query(int i,int l,int r){
    if(tree[i].l>=l && tree[i].r<=r)
        return tree[i].sum;
    if(tree[i].r<l || tree[i].l>r)
		return 0;
    push_down(i);
    int res=0;
    if(tree[i*2].r>=l)
		res+=query(i*2,l,r);
    if(tree[i*2+1].l<=r)
		res+=query(i*2+1,l,r);
    return res;
}

ok,以上就是本期的全部内容。如果有什么问题,请在评论区指正。我们下期再见!

友情提醒:洛谷P3368的代码有问题,请不要无脑Ctrl C+Ctrl V

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/408602.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Chiplet技术与汽车芯片(二)

目录 1.回顾 2.Chiplet的优势 2.1 提升芯片良率、降本增效 2.2 设计灵活&#xff0c;降低设计成本 2.3 标准实行&#xff0c;构建生态 3.Chiplet如何上车 1.回顾 上一篇&#xff0c;我们将来芯粒到底是什么东西&#xff0c;本篇我们来看芯粒技术的优势&#xff0c;以及它…

5.1 Ajax数据爬取之初介绍

目录 1. Ajax 数据介绍 2. Ajax 分析 2.1 Ajax 例子 2.2 Ajax 分析方法 &#xff08;1&#xff09;在网页页面右键&#xff0c;检查 &#xff08;2&#xff09;找到network&#xff0c;ctrl R刷新 &#xff08;3&#xff09;找 Ajax 数据包 &#xff08;4&#xff09;…

多线程相关(4)

线程安全-下 使用层面锁优化减少锁的时间&#xff1a;减少锁的粒度&#xff1a;锁粗化&#xff1a;使用读写锁&#xff1a;使用CAS&#xff1a; 系统层面锁优化自适应自旋锁锁消除锁升级偏向锁轻量级锁重量级锁 ThreadLocal原理ThreadLocal简介原理ThreadLocal内存泄漏 HashMap…

VMware使用虚拟机,开启时报错:无法连接虚拟设备 0:0,因为主机上没有相应的设备。——解决方法

检查虚拟机配置文件并确保物理设备已正确连接。 操作&#xff1a; 选中虚拟机&#xff0c;打开设置&#xff0c;点击CD/DVD。在连接处选择使用ISO镜像文件

fpga_硬件加速引擎

一 什么是硬件加速引擎 硬件加速引擎&#xff0c;也称硬件加速器&#xff0c;是一种采用专用加速芯片/模块替代cpu完成复杂耗时的大算力操作&#xff0c;其过程不需要或者仅需要少量cpu参与。 二 典型的硬件加速引擎 典型的硬件加速引擎有GPU&#xff0c;DSP&#xff0c;ISP&a…

【二分查找】【浮点数的二分查找】【二分答案查找】

文章目录 前言一、二分查找&#xff08;Binary Search&#xff09;二、浮点数的二分查找三、二分答案总结 前言 今天记录一下基础算法之二分查找 一、二分查找&#xff08;Binary Search&#xff09; 二分查找&#xff08;Binary Search&#xff09;是一种在有序数组中查找目…

1 Nacos数据持久化方式

Nacos 支持两种数据持久化方式&#xff0c;一种是利用内置的数据库&#xff0c;另一种是利用外置的数据源。 1、内置数据库支持 Nacos 默认内置了一些数据存储解决方案&#xff0c;如内嵌的 Derby 数据库。 这种内置方式主要用于轻量级或测试环境。 2、外置数据库支持 对于生…

【RN】学习使用 Reactive Native内置UI组件

简言 当把导航处理好后&#xff0c;就可以学习使用ui组件了&#xff08;两者没有先后关系&#xff0c;个人习惯&#xff09;。 在 Android 和 iOS 开发中&#xff0c;一个视图是 UI 的基本组成部分&#xff1a;屏幕上的一个小矩形元素、可用于显示文本、图像或响应用户输入。甚…

如何使用逻辑回归处理多标签问题?

逻辑回归处理多分类 1、背景描述2、One vs One3、One vs Rest4、从Sigmoid到Softmax的推导 1、背景描述 逻辑回归本身只能用于二分类问题&#xff0c;如果实际情况是多分类的&#xff0c;那么就需要对模型进行一些改动。下面介绍三种常用的将逻辑回归用于多分类的方法 2、One …

目标跟踪之KCF详解

High-Speed Tracking with Kernelized Correlation Filters 使用内核化相关滤波器进行高速跟踪 大多数现代跟踪器的核心组件是判别分类器&#xff0c;其任务是区分目标和周围环境。为了应对自然图像变化&#xff0c;此分类器通常使用平移和缩放的样本补丁进行训练。此类样本集…

用Python实现创建十二星座数据分析图表

下面小编提供的代码中&#xff0c;您已经将pie.render()注释掉&#xff0c;并使用了pie.render_to_file(十二星座.svg)来将饼状图渲染到一个名为十二星座.svg的文件中。这是一个正确的做法&#xff0c;如果您想在文件中保存图表而不是在浏览器中显示它。 成功创建图表&#xf…

嵌入式软件分层设计的思想分析

“嵌入式开发&#xff0c;点灯一路发” 那今天我们就以控制LED闪烁为例&#xff0c;来聊聊嵌入式软件分层: ——————————— | | | P1.1 |-----I<|--------------<| | | | P2.1 |-------------/ ---------…

MyBatis的⾼级映射及延迟加载

MyBatis的⾼级映射及延迟加载 一、多对一1.方式一&#xff1a;级联属性映射2.方式二&#xff1a;association3.方式三&#xff1a;分步查询 二、一对多1.方式一&#xff1a;collection2.方式二&#xff1a;分步查询 三、延迟加载&#xff08;懒加载&#xff09;1.分步查询的优点…

【C++】类和对象之拷贝构造函数篇

个人主页 &#xff1a; zxctscl 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 文章目录 1. 前言2. 传值传参和传引用传参3. 概念4. 特征 1. 前言 在前面学习了6个默认成员函数中的构造函数和析构函数 【C】构造函数和析构函数详解&#xff0c;接下来继续往后看拷…

uvloop,一个强大的 Python 异步IO编程库!

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站零基础入门的AI学习网站~。 目录 ​编辑 前言 什么是uvloop库&#xff1f; 安装uvloop库 使用uvloop库 uvloop库的功能特性 1. 更…

nodejs+vue+ElementUi废品废弃资源回收系统

系统主要是以后台管理员管理为主。管理员需要先登录系统然后才可以使用本系统&#xff0c;管理员可以对系统用户管理、用户信息管理、回收站点管理、站点分类管理、站点分类管理、留言板管理、系统管理进行添加、查询、修改、删除&#xff0c;以保障废弃资源回收系统系统的正常…

【Linux】部署单机项目(自动化启动)

目录 一.jdk安装 二.tomcat安装 三.MySQL安装 四.部署项目 一.jdk安装 1.上传jdk安装包 jdk-8u151-linux-x64.tar.gz 进入opt目录&#xff0c;将安装包拖进去 2.解压安装包 防止后面单个系列解压操作&#xff0c;我这边就直接将所有的要用的全部给解压&#xff0c;如下图注…

2024 高级前端面试题之 计算机通识(基础) 「精选篇」

该内容主要整理关于 计算机通识&#xff08;基础&#xff09; 的相关面试题&#xff0c;其他内容面试题请移步至 「最新最全的前端面试题集锦」 查看。 计算机基础精选篇 一、网络1.1 UDP1.2 TCP1.3 HTTP1.4 DNS 二、数据结构2.1 栈2.2 队列2.3 链表2.4 树2.5 堆 三、算法3.1 时…

计算机毕业设计-SSM课程题库管理系统 18655(赠送源码数据库)JAVA、PHP,node.js,C++、python,大屏数据可视化等

毕业设计&#xff08;论文&#xff09; SSM课程题库管理系统 学 院 专 业 班 级 学 号 学生姓名 指导教师 完成日期…

vSphere高可用架构---HA简介

1.高可用性 2.不同级别的高可用&#xff1a; 1&#xff09;应用程序级别&#xff0c;2&#xff09;操作系统级别&#xff0c;3&#xff09;虚拟化级别&#xff0c;4&#xff09;物理层级别 不同级别的高可用举例&#xff1a; 应用程序级别的高可用性。例如&#xff1a;Oracl…