当前位置:网站首页>线段树
线段树
2022-07-18 23:32:00 【casperwu】
1. 定义
线段树是一种基于分治思想的二叉树结构,常用于统计区间内的信息。
特征:
线段树的每个节点都代表一个闭区间 线段树具有唯一的根节点,代表的区间是整个统计范围 线段树的每个叶节点都代表一个长度为1的元区间 对于每个内部节点[l, r], 它的左子节点是[l, mid], 右子节点是[mid+1, r], 其中mid = (l + r) / 2 向下取整

2. 线段树的存储
由于线段树是一棵二叉树,根据定义可以得到除了最后一层的结点外,它是一棵满二叉树,因此可以使用数组来存储线段树。
假设原始数组的长度是N,使用线段树存储时需要开4N长度。
证明: 由于倒数第二层的结点数 < N,就取上限为N,则从倒数第二层到根节点最多有2N - 1个结点,最后一层的结点数 < 2N,因此总共的节点数不会超过4N。
3. 模板题目

3.1 思路
根据题意,每次输入的数据是动态的,但是在建立树状数组时需要提前知道数据的长度。因此可以先预先假设需要建立的树状数组的长度是 m 个, 每次添加一个新的数据时,可以看做是在相应的位置上将该值修改为添加的值。即先占坑,在需要时修改该值即可。
3.2 模板代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 2e5 + 5;
struct Node {
int l, r;
int dat; // 存储区间[l, r] 之间的最大值
} tr[N * 4]; // 线段树需要开4倍空间
int m, p;
// 用于从子节点更新父节点的数据, 根据具体的需求实现会不一样
// 本题是设置最大值
void pushup(int p) {
tr[p].dat = max(tr[p << 1].dat, tr[p << 1 | 1].dat);
}
// 由于本题中最开始初始化的线段树是用来占位的, 没有值
void build(int p, int l, int r) {
tr[p].l = l, tr[p].r = r;
if(l == r) {
// 用于占位, 没有值, 因此可以不赋值
return;
}
int mid = l + r >> 1;
// p << 1 等价于 p * 2, p << 1 | 1 等价于 P * 2 + 1
build(p << 1, l, mid), build(p << 1 | 1, mid + 1, r);
// 也不需要pushup赋值操作
}
void update(int p, int x, int v) {
if(tr[p].l == tr[p].r) { // 递归边界, 递归到了叶子节点
tr[p].dat = v;
return;
}
int mid = tr[p].l + tr[p].r >> 1;
if(x <= mid) update(p << 1, x, v); // 递归左侧
else update(p << 1 | 1, x, v); // 递归右侧
pushup(p); // 更新当前节点的值
}
int query(int p, int left, int right) {
// 树上的区间完全包含在目标区间中, 直接返回
if(left <= tr[p].l && tr[p].r <= right) return tr[p].dat;
int ans = 0; // 由于输入的值一定是大于0的, 因此可以用0来表示最小值
int mid = tr[p].l + tr[p].r >> 1;
if(left <= mid) ans = max(ans, query(p << 1, left, right));
if(right > mid) ans = max(ans, query(p << 1 | 1, left, right));
return ans;
}
int main() {
cin >> m >> p;
// 构建线段树
build(1, 1, m);
int n = 0, last = 0; // n 用于记录当前输入的数据个数, last 记录上次查询的结果
string type; int x;
while(m--) {
cin >> type >> x;
if(type == "Q") { // 查询操作
last = query(1, n - x + 1, n);
cout << last << endl;
} else {
n++; // 输入的数的个数 +1
update(1, n, ((LL)x + last) % p);
}
}
return 0;
}
边栏推荐
- Review of leetcode question brushing (question No.: 94, 17, interview questions 17, 102, 215, 1, 21)
- Normalestimation normal vector estimation theory and code -- PCL source code Notes
- Hands on practice - teach you how to make an intelligent fish tank with STM32
- 「接口测试入门课」打卡学习 day03:理解接口测试的关键逻辑
- 一个身份证可开几个券商帐户?开户安全吗
- 高端茶领域的产品主义者,曹先生因何选择了瑞风L6 MAX?
- day03_1_idea教程
- Usage and meaning of [optional chain], [null value merging operator] and [null value assignment operator] of JS
- Intelligent cockpit fighting method of Internet manufacturers
- [programming questions] [scratch Level 2] 2020.12 forest party
猜你喜欢
[OC学习笔记]GCD复习
高端茶领域的产品主义者,曹先生因何选择了瑞风L6 MAX?
Intelligent cockpit fighting method of Internet manufacturers
B树-删除
[programming questions] [scratch Level 3] 2022.03 catch game
The line chart can show the data trend and filter the data at the same time
selenium的下拉+无头浏览器
js数据类型获取
BN (batch normalization) principle
HCIP第八天笔记整理(OSPF路由控制、附录E、防环、最短路径计算、重发布))
随机推荐
数组指针辨析
Everything is available Cassandra: the fairy database behind Huawei tag
etcdv3实战(三)-PrevKV说明及相关操作
【obs-studio开源项目从入门到放弃】obs高级输出内存泄露
在同花顺网上开户安全吗
Report control fastreport Net tutorial: how to use report components in Visual Studio
Party documentation. Most API. Based on this Aage, shengteng
An improved one millisecond mobile backbone paper notes
小白如何再中信开通靠谱安全的账户?
[programming questions] [scratch Level 3] 2022.03 catch game
字节跳动(抖音)软件测试月薪23K岗、技术二面面试题最新出炉
Intelligent cockpit fighting method of Internet manufacturers
B树-删除
BN (batch normalization) principle
DDD based on ABP -- warehousing practice
Sword finger offer 42: the maximum sum of continuous subarrays
selenium的各种操作
MoCo V1:视觉领域也能自监督啦
Is it safe to open an account online in flush
HCIP第八天笔记整理(OSPF路由控制、附录E、防环、最短路径计算、重发布))