【蓝桥杯】线段树

一.线段树

1.定义:

线段树是算法竞赛中常用的用来维护 区间信息 的数据结构。

线段树可以在O(logN) 的时间复杂度内实现单点修改、区间修改、区间查询(区间求和,求区间最大值,求区间最小值)等操作。

2.结构:

        线段树将每个长度不为1的区间划分成左右两个区间递归求解,把整个线段划分为一个树形结构,通过合并左右两区间信息来求得该区间的信息。这种数据结构可以方便的进行大部分的区间操作。

        给出一个数组A ={11,22,33,44,55},我们开始针对这个数组构造线段树。

        首先将根节点编号设为1,用数组D来保存线段树,其中D_i保存线段树上编号为i的结点的值。每个结点所维护的值就是这个节点所表示的区间总和,如下图所示:

        通过数据结构的知识,我们可知:i结点的左孩子的编号为2i,右孩子的编号为2i+1。

如果 D_i表示的区间为[s,t],那么D_i的左孩子D_{2i}表示的区间为[s,\frac{s+t}{2}]D_i的右孩子D_{2i+1}表示的区间为[\frac{s+t}{2}+1,t]

3.建立:

我们选择堆式存储,即用数组对线段树进行存储。

//线段树
#include <iostream>using namespace std;const int N=1e4+10;
int a[N],d[N];void merge(int x){d[x]=d[2*x]+d[2*x+1];
}void build(int x,int fisrt,int end){if(fisrt==end){d[x]=a[fisrt];return;}int mid=(fisrt+end)/2;build(2*x, fisrt, mid);build(2*x+1, mid+1, end);merge(x);
}

这里注意一点,对于一个节点来说,要么没有孩子节点,要么就有两个孩子节点。

4.区间查询: 

区间查询是指:求区间[l,r]的总和,求区间最大值最小值等操作。

int query(int x,int l,int r,int L,int R){//x表示当前查询的结点编号,[r,l]表示当前查找结点所表示的区间,[R,L]表示需要查找的区间if(l>=L&&r<=R){return d[x];}int mid=(l+r)/2;int result=0;if(L<=mid){result+=query(2*x, l, mid, L, R);}if(R>mid){result+=query(2*x+1, mid+1, r, L, R);}return result;
}

 5.单点修改:

主要就是修改了一个值以后,后续的那一支的树的分支都要修改。

//单点修改
void change(int p,int l,int r,int x,int v){//将a[x]修改为v//p表示当前节点的编号,[l,r]表示当前所处的区间if(r==l){d[p]=v;return;}int mid=(l+r)/2;if(x<=mid)change(p*2, l, mid, x, v);elsechange(p*2+1, mid+1, r, x, v);merge(p);
}

6.区间修改:

在线段树中会遇到区间更新的情况,例如在区间求和问题中,令[a,b]区间内的值全部加c,若此时再采用单点更新的方法,就会耗费大量时间,这个时候就要用到懒标记(lazy标记)来进行区间更新了。

lazy标记:主要思想是,如果进行单点更新太费时间,增量就由上层暂存。lazy标记保存的是增量increment。

1)区间增加某一值

//区间更新(增加某一值)
void update(int l,int r,int c,int s,int t,int p){//[l,r]为修改区间,c为被修改区间的元素的变化量//[s,t]为当前节点所包含的区间,p为当前节点的编号if(l<=s&&t<=r){//当前区间是被修改区间的子区间d[p]+=(t-s+1)*c;//加增量lazy[p]+=c;//标记return;}int mid=(s+t)/2;if(lazy[p]!=0&&s!=t){//当前节点的lazy标记不为0,更新当前节点的两个子节点的值和lazy标记d[p*2]+=lazy[p]*(mid-s+1);lazy[p*2]+=lazy[p];d[p*2+1]+=lazy[p]*(t-mid);lazy[p*2+1]+=lazy[p];lazy[p]=0;//清空当前节点的lazy标志}if(l<=mid)update(l,r,c,s,mid,2*p);if(r>mid)update(l, r, c, mid+1, t, p*2+1);merge(p);//这里是因为有可能是包含了左/右区间的部分区间,所以要重新更新一下上层节点的值
}

 2)区间查询(带lazy标志)

//区间查询
int getsum(int l,int r,int s,int t,int p){//[l,r]为查询区间,[s,t]为当前节点包含的区间,p为当前节点的编号if(l<=s&&t<=r){return d[p];}int mid=(s+t)/2;if(lazy[p]>0){//当前节点的lazy标记不为空,更新当前节点的两个子节点的值和lazy标记//此处,若是p节点没有子节点,是不可能的,因为查询到了该区间,就意味着这个区间一定是包含了待查询区间的子区间的//如果p节点没有子区间,那么s必定等于t,这个区间一定是待查询区间的子区间,在上一个if就已经返回了d[p*2]+=lazy[p]*(mid-s+1);lazy[p*2]+=lazy[p];d[p*2+1]+=lazy[p]*(t-mid);lazy[p*2+1]+=lazy[p];lazy[p]=0;//当前节点的lazy标志清空}int sum=0;if(l<=mid)sum+=getsum(l, r, s, mid, p*2);if(r>mid)sum+=getsum(l, r, mid+1, t, p*2+1);return sum;
}

3)将某一区间的值都修改为某一值

如果是修改为指定值,那么配套的区间查询函数也必须修改。

//区间修改为指定值
void fix(int l,int r,int s,int t,int p,int x){//[l,r]为查询区间,[s,t]为当前节点包含的区间,p为当前节点的编号//x为将[l,r]的区间修改为的指定值if(l<=s&&r>=t){d[p]=x*(t-s+1);lazy[p]=x;return;}int mid=(s+t)/2;if(lazy[p]>0){d[p*2]=lazy[p]*(mid-s+1);lazy[p*2]=lazy[p];d[p*2+1]=lazy[p]*(t-mid);lazy[p*2+1]=lazy[p];lazy[p]=0;//清空当前节点的lazy标志}if(l<=mid)fix(l, r, s, mid, p*2, x);if(r>mid)fix(l, r, mid+1, t, p*2+1, x);merge(p);
}
//区间查询
int get_sum(int l,int r,int s,int t,int p){if(l<=s&&r>=t){return d[p];}int mid=(s+t)/2;if(lazy[p]>0){d[p*2]=lazy[p]*(mid-s+1);lazy[p*2]=lazy[p];d[p*2+1]=lazy[p]*(t-mid);lazy[p*2+1]=lazy[p];lazy[p]=0;}int sum=0;if(l<=mid)sum+=get_sum(l, r, s, mid, p*2);if(r>mid)sum+=get_sum(l, r, mid+1, t, p*2+1);return sum;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【论文阅读】Improved Denoising Diffusion Probabilistic Models

Improved Denoising Diffusion Probabilistic Models 文章目录 Improved Denoising Diffusion Probabilistic Models概述Improving the Log-likelihoodLearning ∑ θ ( x t , t ) \sum_{\theta}(x_{t}, t) ∑θ​(xt​,t)Improving the Noise ScheduleReducing Gradient Nois…

基于Pnpm + Turborepo + QianKun的微前端+Monorepo实践

基于Pnpm Turborepo QianKun的微前端Monorepo实践 背景 微前端一般都会涉及多个代码库&#xff0c;很多时候要一个一个代码库地去开发维护和运行&#xff0c;很不方便&#xff0c;这种时候引入Monorepo搭配微前端就能很好地解决这种问题&#xff0c;一个代码库就可以完成整…

Spring Cloud Alibaba微服务从入门到进阶(三)(Spring Cloud Alibaba)

Spring Cloud Alibaba是spring Cloud的子项目 Spring Cloud Alibaba的主要组件&#xff08;红框内是开源的&#xff09; Spring Cloud是快速构建分布式系统的工具集&#xff0c; Spring Cloud提供了很多分布式功能 Spring Cloud常用子项目 项目整合 Spring Cloud Alibaba …

友塔游戏测试开发笔面经验

题目一 给定任意非负整数M&#xff0c;判断其能否表达为 M 2 ^a 2 ^b(a和b为非负整数)&#xff0c;若可以输出a和b&#xff0c;若不能输出-1&#xff1b; 例如&#xff1a; 输入&#xff1a;6 输出: “1 2” 分析&#xff1a; void findAB(int M){} 为解决问题的主函数 …

优选算法[1]

目录 1.双指针&#xff1b; 2.滑动窗口&#xff1b; 3.二分查找&#xff1b; 4.前缀和&#xff1b; 1.双指针&#xff1b; 包括对撞指针和快慢指针(一般用来循环&#xff09;&#xff1b; 题目类型&#xff1a;移动零&#xff0c;复写零&#xff0c;快乐数&#xff0c;盛…

【每日力扣】235. 二叉搜索树的最近公共祖先与39. 组合总和问题描述

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害。 235. 二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义…

Python中类方法和静态方法的区别你知道吗?

​1.类方法 通过 classmethod 装饰器修饰的方法就是类方法 类方法可以通过类名或对象名调用&#xff0c;但是一般情况下使用类名调用&#xff08;节省内存&#xff09; 类方法中没有self.在类方法中不可以使用其它对象的属性和方法 类方法中一般会有一个参数cls&#xff0c;…

Crc冗余校验码设计

串行电路的位置&#xff0c;有异或门的地方是1&#xff08;生成多项式&#xff09; 简单的来说&#xff0c;如果最高位Q4 为0 的话&#xff0c;那么直接和 0 进行异或的话&#xff0c;实现的也是自己本身&#xff0c;直接左移就可以了 如果最高是1的话&#xff0c;那么就要和生…

【数据结构与算法】:选择排序与快速排序

&#x1f525;个人主页&#xff1a; Quitecoder &#x1f525;专栏&#xff1a;数据结构与算法 我的博客即将同步至腾讯云开发者社区&#xff0c;邀请大家一同入驻&#xff1a;腾讯云 欢迎来到排序的第二个部分&#xff1a;选择排序与快速排序&#xff01; 目录 1.选择排序1.…

如何export windows中的环境变量

在大语言模型&#xff08;LLM&#xff09;学习过程中&#xff0c; 利用 jupyter 导入环境变量时出现以下问题&#xff0c; C:\Users\zhangxuantao>export SENSENOVA_SKxxxxxx export 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 原因是学习教程中用…

VTK安装(C++)并配置vs

准备工作&#xff1a; 1.VTK下载包(此教程使用VTK8.2.0) 2.CMAKE(此教程使用3.29.0) 在此不过多赘述&#xff0c;可在网上搜索cmake安装 3.visual studio(此教程使用vs2019) VTK下载及编译&#xff1a; 1、找到自己适合的VTK版本,我选择的是VTK8.2.0。 1.1 官网下载&#xff…

天水麻辣烫榜上有名!2024适合普通人的创业项目!2024最适合创业的三大行业!2024热门创业项目!

1、天水麻辣烫 最近济南6天开了4家甘肃麻辣烫天天爆满 有店日营业额破万元有店主飞甘肃天水学习5天回来迅速开店&#xff01;选择天水麻辣烫作为创业项目绝对是一个明智的选择。趁着现在的热度&#xff0c;开设一家门店&#xff0c;借助其已经积累的名气和口碑&#xff0c;创业…