线段树(学习笔记)

news/2025/1/20 19:04:31/文章来源:https://www.cnblogs.com/XichenOC/p/18682335

线段树

例题

一.功能:

线段树可以用来处理区间问题如 “区间和” 虽然区间和可以用前缀和解决,用\(O(1)\) 的复杂度进行查询,但修改需要\(O(n)\)的复杂度。同理差分可以以\(O(1)\)的复杂度进行修改,但需要\(O(n)\)的复杂度进行查询。
所以线段树可以同时用\(O(logn)\)的复杂度进行查询和修改。同时线段树可以维护多种不同的区间关系,如区间乘区间最大数

二.原理:

利用了分治的思想,将一个数列进行二分建树用根来维护此小区间的区间关系,如区间最大值一个数列的最大值也就等于它左半部分的最大值和右半部分的最大值的最大值。

三.实现(以例题为例);

1.建立线段树:

运用递归的思想,若当前根节点为\(p\)则其左儿子\(lc\)\(p<<1\),右儿子为\(p<<1|1\)。这样就可以用数组表示线段树,在建起左子树和右子树,最后在根据左右子树的关系给当前根节点进行赋值\(sum\)。时间复杂度为\(nlogn\)

void build(int p,int l,int r){if(l==r){tr[p].sum=a[l];return;}int mid=(l+r)>>1;build(lc,l,mid);build(rc,mid+1,r);tr[p].sum=tr[lc].sum+tr[rc].sum;
}

2.单点修改;

我们只需要知道要修改的点的坐标,然后递归遍历,看它是在左儿子的区间内还是右儿子的区间,直到找到这个数,在回溯修改所有的根节点的值。时间复杂度为\(logn\)

void update(int p,int l,int r,int add,int p){if(l==r){tr[p].sum+=add;return;}int mid=(l+r)>>1;if(l<=p && p<=mid)update(lc,l,mid,add,p);if(mid+1<=p && p<=r)update(rc,mid+1,r,add,p);tr[p].sum=tr[lc].sum+tr[rc].sum;
}

3.区间修改:

但如果要修改整个区间的值时该怎么办,若是一个一个单点修改那时间复杂度为\(nlogn\),比暴力还要慢。这时候我们可以想到加一个懒标志,若当前递归到的区间在我要修改的区间之内,就不往下遍历了,等后面需要往下走的时候顺便修改了,这样就可以把时间复杂度压缩到\(logn\)

void Add(int p,int l,int r,int add){tr[p].add+=add;tr[p].sum+=add*(r-l+1);
} 
void push_down(int p,int l,int r){int mid=(l+r)>>1;if(tr[p].add==0)return;Add(lc,l,mid,tr[p].add);Add(rc,mid+1,r,tr[p].add);tr[p].add=0;
}
void update(int p,int l,int r,int add,int ll,int rr){if(ll<=l && r<=rr){Add(p,l,r,add);return;}int mid=(l+r)>>1;push_down(p,l,r);if(ll<=mid)update(lc,l,mid,add,ll,rr);if(rr>mid)update(rc,mid+1,r,add,ll,rr);tr[p].sum=tr[lc].sum+tr[rc].sum;
}

4.查询:

查询一段区间时,我们不需要一个一个遍历,我只需要找到所有包含于查询区间的值,最后累加即可,也是用递归查找,同时在查询中可以顺便转移懒标志\(pushdown\)一下即可

int query(int p,int l,int r,int ll,int rr){if(ll<=l && r<=rr){return tr[p].sum;}push_down(p,l,r);int mid=(l+r)>>1;int res=0;if(ll<=mid)res+=query(lc,l,mid,ll,rr);if(rr>mid)res+=query(rc,mid+1,r,ll,rr);return res;
}

四.完整代码:

#include<bits/stdc++.h>
#define lc p<<1
#define rc p<<1|1
#define int long long
using namespace std;
const int N=100010;
struct edge{int sum,add;
}tr[N*4];
int a[N];
void Add(int p,int l,int r,int add){tr[p].add+=add;tr[p].sum+=add*(r-l+1);
} 
void push_down(int p,int l,int r){int mid=(l+r)>>1;if(tr[p].add==0)return;Add(lc,l,mid,tr[p].add);Add(rc,mid+1,r,tr[p].add);tr[p].add=0;
}
void build(int p,int l,int r){if(l==r){tr[p].sum=a[l];return;}int mid=(l+r)>>1;build(lc,l,mid);build(rc,mid+1,r);tr[p].sum=tr[lc].sum+tr[rc].sum;
}
void update(int p,int l,int r,int add,int ll,int rr){if(ll<=l && r<=rr){Add(p,l,r,add);return;}int mid=(l+r)>>1;push_down(p,l,r);if(ll<=mid)update(lc,l,mid,add,ll,rr);if(rr>mid)update(rc,mid+1,r,add,ll,rr);tr[p].sum=tr[lc].sum+tr[rc].sum;
}
int query(int p,int l,int r,int ll,int rr){if(ll<=l && r<=rr){return tr[p].sum;}push_down(p,l,r);int mid=(l+r)>>1;int res=0;if(ll<=mid)res+=query(lc,l,mid,ll,rr);if(rr>mid)res+=query(rc,mid+1,r,ll,rr);return res;
}
signed 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,x,y;cin>>op>>x>>y;if(op==1){int k;cin>>k;update(1,1,n,k,x,y);}if(op==2){cout<<query(1,1,n,x,y)<<endl;}}
} 

五.练习:

1.P1198 [JSOI2008] 最大数 题解
2.P4588 [TJOI2018] 数学计算 题解
3.P2471 [SCOI2007] 降雨量 题解
4.P4145 上帝造题的七分钟 2 / 花神游历各国 题解
5.P2391 白雪皑皑 题解
6.P4513 小白逛公园 题解

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

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

相关文章

U455764 The Rotation Game

U455764 The Rotation Game 题目理解 本题要求移动\(A-H\)中的一列或一行,使其整个一行和一列的数字移动,使最后的中间8个的数字相同。求最少需要移动的步数和它的操纵顺序思路 1.本题可以很显然的想到用 \(BFS\) 来枚举执行不同字母操作后结果,但每 \(BFS\) 一次就会增加八…

BUU SQL COURSE 2

BUU SQL COURSE 2 BUU SQL COURSE 2 和前面那题差不多,但是注一下找到的登录成功但是显示 fault。 注一下别的看一下,在另一个数据库里找到了 flag。本文来自博客园,作者:Maplisky,转载请注明原文链接:https://www.cnblogs.com/lbh2021/p/18682313

PotPlayer 配置安装

目录一、下载1、官网链接2、微软商店 Microsoft Store二、安装1、双击安装包2、选择字体3、安装向导下一步4、接收许可协议5、选择组件及关联6、选择安装位置7、硬解选项三、设置1、关闭自动更新2、左键单双击设置3、视频下自动隐藏3.1、效果对比4、播放信息显示设置4.1、效果5…

2024年春秋杯网络安全联赛冬季赛部分wp

部分附件下载地址: https://pan.baidu.com/s/1Q6FjD5K-XLI-EuRLhxLq1Q 提取码: jay1 Misc day1-简单算术 根据提示应该是异或下载文件是一个字符串,写个代码字符串异或解密,由于需要密钥,所以先对单字节密钥进行爆破解密 爆破出flag代码如下: cipher_text = "ys~xdg/…

大夏龙雀DX-WF25(ESP32C2)蓝牙WIFI模块试用体验

模块尺寸跟引脚兼容常见的ESP8266 12-F模块,使用非常简单,vcc接3.3v,gnd接地,rx连接ch340的tx,tx连接ch340的rx即可。 如果需要通过urat下载程序,只需要把io9的引脚接地就行(下载完程序记得断开io9跟gnd的连接,否则程序无法运行)。芯片用的是ESP32C2(ESP8684),很遗…

1.20 前端连接数据库

今天完成了项目的网页前端与后端数据库的连接,已经能够将前端填写的内容添加到mysql数据库 例如页面如下:数据库内容:明天开始编写下一个功能

【vjudge训练记录】大一寒假专项训练——枚举算法

训练情况A题 给定 \((x,y)\),倒着枚举地毯的范围是否覆盖 \((x,y)\),如果覆盖直接输出,如果全部枚举完都没有则输出 -1点击查看代码 #include <bits/stdc++.h> // #define int long long #define endl \nusing namespace std;void solve(){int n; cin>>n;int x[…

Khepri C2 framework beacons记录(之前的)

1、背景 在查看进程时发现可疑隐藏进程,名称为.test(.test.93627),隐藏文件,很可疑,于是查了下进程日志发现如下:/private/tmp/.test /private/var/db/oah/4b8f81eadefb42da07e9e88fa7905df57faec82d8621008e0ae4a04d81e2169f/bb9595accf35a51de80f42e656bdb2217238af58…

(重要***)查询自己需要的SQL语句

凡是指标相关的,先清空相关干扰条件,然后点击确认,比如加载性能里的列表页面,要查慢加载次数这个指标这个时候去这个数据库 写SQL语句select* fromquery_log ql whereql.user_name = sheng.yu-n@msxf.com order byexec_time desc limit 50然后找到自己对应操作的SQL 通过结…

最强截图录屏工具ShareX v17.0.0 中文绿色版

软件介绍 ShareX 是一款功能强大的屏幕截图和屏幕录制工具,可用于创建高质量的屏幕截图、动画 GIF 和屏幕录像,并提供多种上传选项,使用户能够轻松地将它们共享到互联网上。除此之外,它还支持多种自定义功能,例如图像编辑、颜色拾取、OCR 文字识别等。软件功能快速截图:简…

动态可视化:一步步拆解LSTM和GRU

转自:https://zhuanlan.zhihu.com/p/47907312 编者按:关于LSTM,之前我们已经出过不少文章,其中最经典的一篇是chrisolah的《一文详解LSTM网络》,文中使用的可视化图片被大量博文引用,现在已经随处可见。但正如短视频取代纯文字阅读是时代的趋势,在科普文章中,用可视化取…

【大屏可视化】系统(Vue3 + ECharts5)快速实现和应用 ️

🎶【大屏可视化】系统(Vue3 + ECharts5)🎶这八部~~按照,难易的顺序来进行绘制!!!💯横向柱形图竖向柱形图雷达图环形图关系图数据云图数据展示图地图可视化02:基于 vite 与 tailwindcss 创建大屏可视化项目 1,基于 vite 创建项目,使用: npm create vite@latest …