当前位置:网站首页>【线段树实战】最近的请求次数 + 区域和检索 - 数组可修改+我的日程安排表Ⅰ/Ⅲ
【线段树实战】最近的请求次数 + 区域和检索 - 数组可修改+我的日程安排表Ⅰ/Ⅲ
2022-07-06 22:03:00 【爱写Bug的王六六】
之前写的文章:在语雀上写的线段树解析以及题目实战
线段树模板:
/** * 线段树(动态开点) **/
public class SegmentTreeDynamic {
//线段树数据结构
class Node {
Node left, right;
int val, add;
}
private int N = (int) 1e9;
//先创建第一个节点
private Node root = new Node();
//更新
public void update(Node node, int start, int end, int l, int r, int val) {
if (l <= start && end <= r) {
node.val += (end - start + 1) * val;
node.add += val;
return ;
}
int mid = (start + end) >> 1;
pushDown(node, mid - start + 1, end - mid);
//更新左右区间
if (l <= mid) update(node.left, start, mid, l, r, val);
if (r > mid) update(node.right, mid + 1, end, l, r, val);
pushUp(node);
}
//查询
public int query(Node node, int start, int end, int l, int r) {
if (l <= start && end <= r) return node.val;
int mid = (start + end) >> 1, ans = 0;
pushDown(node, mid - start + 1, end - mid);
if (l <= mid) ans += query(node.left, start, mid, l, r);
if (r > mid) ans += query(node.right, mid + 1, end, l, r);
return ans;
}
//向上更新节点值
private void pushUp(Node node) {
node.val = node.left.val + node.right.val;
}
//下推
private void pushDown(Node node, int leftNum, int rightNum) {
//节点无左右节点则新建
if (node.left == null) node.left = new Node();
if (node.right == null) node.right = new Node();
if (node.add == 0) return ;
node.left.val += node.add * leftNum;
node.right.val += node.add * rightNum;
// 对区间进行「加减」的更新操作,下推懒惰标记时需要累加起来,不能直接覆盖
node.left.add += node.add;
node.right.add += node.add;
node.add = 0;
}
}
● 对于表示为「区间和」且对区间进行「加减」的更新操作的情况,在更新节点值的时候『需要️左右孩子区间叶子节点的数量』;我们在下推懒惰标记的时候『需要累加』(这种情况和模版一致) 如题目 最近的请求次数
● 对于表示为「区间和」且对区间进行「覆盖」的更新操作的情况,我们在更新节点值的时候『需要️左右孩子区间叶子节点的数量』;我们在下推懒惰标记的时候『不需要累加』!!(因为是覆盖操作!!) 如题目 307. 区域和检索 - 数组可修改
● 对于表示为「区间最值」 且对区间进行「加减」的更新操作的情况,我们在更新节点值的时候『不需要️左右孩子区间叶子节点的数量』;我们在下推懒惰标记的时候『需要累加』!! 如题目 我的日程安排表 I、 我的日程安排表 III
注意:
对于题目 最近的请求次数 和 307. 区域和检索 - 数组可修改 可以「不用️左右孩子区间叶子节点的数量」
为什么??因为这两个题目是「点更新」,在介绍线段树更新的时候:「点更新」和「区间更新」可以合并成一种,「点更新」就是更新长度为 1 的区间嘛。
上面两个题目调用更新函数的方式为:
- update(root, 1, N, t, t, 1);
- update(root, 0, N, i, i, nums[i]);
由于区间是一个点,所以一定会更新到叶子节点,故可以不用️左右孩子区间叶子节点的数量!!
最近的请求次数

代码实现:
class RecentCounter {
public RecentCounter() {
}
public int ping(int t) {
update(root, 1, N, t, t, 1);
return query(root, 1, N, Math.max(0, t - 3000), t);
}
// *************** 下面是模版 ***************
class Node {
// 左右孩子节点
Node left, right;
// 当前节点值,以及懒惰标记的值
int val, add;
}
private int N = (int) 1e9;
private Node root = new Node();
public void update(Node node, int start, int end, int l, int r, int val) {
if (l <= start && end <= r) {
node.val += val;
node.add += val;
return ;
}
int mid = (start + end) >> 1;
pushDown(node, mid - start + 1, end - mid);
if (l <= mid) update(node.left, start, mid, l, r, val);
if (r > mid) update(node.right, mid + 1, end, l, r, val);
pushUp(node);
}
public int query(Node node, int start, int end, int l, int r) {
if (l <= start && end <= r) return node.val;
int mid = (start + end) >> 1, ans = 0;
pushDown(node, mid - start + 1, end - mid);
if (l <= mid) ans = query(node.left, start, mid, l, r);
if (r > mid) ans += query(node.right, mid + 1, end, l, r);
return ans;
}
private void pushUp(Node node) {
node.val = node.left.val + node.right.val;
}
private void pushDown(Node node, int leftNum, int rightNum) {
if (node.left == null) node.left = new Node();
if (node.right == null) node.right = new Node();
if (node.add == 0) return ;
node.left.val += node.add * leftNum;
node.right.val += node.add * rightNum;
// 对区间进行「加减」的更新操作,下推懒惰标记时需要累加起来,不能直接覆盖
node.left.add += node.add;
node.right.add += node.add;
node.add = 0;
}
}
307. 区域和检索 - 数组可修改

class NumArray {
public NumArray(int[] nums) {
N = nums.length - 1;
for (int i = 0; i <= N; i++) {
update(root, 0, N, i, i, nums[i]);
}
}
public void update(int index, int val) {
update(root, 0, N, index, index, val);
}
public int sumRange(int left, int right) {
return query(root, 0, N, left, right);
}
//***********下面是模板****************
class Node {
// 左右孩子节点
Node left, right;
// 当前节点值,以及懒惰标记的值
int val, add;
}
private int N;
private Node root = new Node();
//更新
public void update(Node node, int start, int end, int l, int r, int val) {
if (l <= start && end <= r) {
node.val = (end - start + 1) * val;
node.add = val;
return ;
}
int mid = (start + end) >> 1;
pushDown(node, mid - start + 1, end - mid);
if (l <= mid) update(node.left, start, mid, l, r, val);
if (r > mid) update(node.right, mid + 1, end, l, r, val);
pushUp(node);
}
//查询
public int query(Node node, int start, int end, int l, int r) {
if (l <= start && end <= r) return node.val;
int mid = (start + end) >> 1, ans = 0;
pushDown(node, mid - start + 1, end - mid);
if (l <= mid) ans += query(node.left, start, mid, l, r);
if (r > mid) ans += query(node.right, mid + 1, end, l, r);
return ans;
}
//向上
private void pushUp(Node node) {
node.val = node.left.val + node.right.val;
}
//向下
private void pushDown(Node node, int leftNum, int rightNum) {
if (node.left == null) node.left = new Node();
if (node.right == null) node.right = new Node();
if (node.add == 0) return ;
node.left.val = node.add * leftNum;
node.right.val = node.add * rightNum;
node.left.add = node.add;
node.right.add = node.add;
node.add = 0;
}
}
我的日程安排表 III

「节点的值不止可以表示该区间的和」,还可以「表示为当前区间的最值」,该题目存储的就是区间的最大值
代码:
class MyCalendarThree {
public MyCalendarThree() {
}
public int book(int start, int end) {
// 只用到了 update
update(root, 0, N, start, end - 1, 1);
// 最大值即为根节点的值
return root.val;
}
// *************** 下面是模版 ***************
class Node {
// 左右孩子节点
Node left, right;
// 当前节点值,以及懒惰标记的值
int val, add;
}
private int N = (int) 1e9;
private Node root = new Node();
public void update(Node node, int start, int end, int l, int r, int val) {
if (l <= start && end <= r) {
node.val += val;
node.add += val;
return ;
}
pushDown(node);
int mid = (start + end) >> 1;
if (l <= mid) update(node.left, start, mid, l, r, val);
if (r > mid) update(node.right, mid + 1, end, l, r, val);
pushUp(node);
}
public int query(Node node, int start, int end, int l, int r) {
if (l <= start && end <= r) return node.val;
pushDown(node);
int mid = (start + end) >> 1, ans = 0;
if (l <= mid) ans = query(node.left, start, mid, l, r);
if (r > mid) ans = Math.max(ans, query(node.right, mid + 1, end, l, r));
return ans;
}
private void pushUp(Node node) {
// 每个节点存的是当前区间的最大值
node.val = Math.max(node.left.val, node.right.val);
}
private void pushDown(Node node) {
if (node.left == null) node.left = new Node();
if (node.right == null) node.right = new Node();
if (node.add == 0) return ;
node.left.val += node.add;
node.right.val += node.add;
node.left.add += node.add;
node.right.add += node.add;
node.add = 0;
}
}
我的日程安排表 I

根据Ⅲ的解题思路:
class MyCalendar {
public MyCalendar() {
}
public boolean book(int start, int end) {
// 先查询该区间是否为 0
if (query(root, 0, N, start, end - 1) != 0) return false;
// 更新该区间
update(root, 0, N, start, end - 1, 1);
return true;
}
// *************** 下面是模版 ***************
class Node {
// 左右孩子节点
Node left, right;
// 当前节点值,以及懒惰标记的值
int val, add;
}
private int N = (int) 1e9;
private Node root = new Node();
public void update(Node node, int start, int end, int l, int r, int val) {
if (l <= start && end <= r) {
node.val += val;
node.add += val;
return ;
}
pushDown(node);
int mid = (start + end) >> 1;
if (l <= mid) update(node.left, start, mid, l, r, val);
if (r > mid) update(node.right, mid + 1, end, l, r, val);
pushUp(node);
}
public int query(Node node, int start, int end, int l, int r) {
if (l <= start && end <= r) return node.val;
pushDown(node);
int mid = (start + end) >> 1, ans = 0;
if (l <= mid) ans = query(node.left, start, mid, l, r);
if (r > mid) ans = Math.max(ans, query(node.right, mid + 1, end, l, r));
return ans;
}
private void pushUp(Node node) {
// 每个节点存的是当前区间的最大值
node.val = Math.max(node.left.val, node.right.val);
}
private void pushDown(Node node) {
if (node.left == null) node.left = new Node();
if (node.right == null) node.right = new Node();
if (node.add == 0) return ;
node.left.val += node.add;
node.right.val += node.add;
node.left.add += node.add;
node.right.add += node.add;
node.add = 0;
}
}
边栏推荐
- Use facet to record operation log
- How do test / development programmers get promoted? From nothing, from thin to thick
- What is CGI, IIS, and VPS "suggested collection"
- Nanopineo use development process record
- Dab-detr: dynamic anchor boxes are better queries for Detr translation
- 数学分析_笔记_第10章:含参变量积分
- 主设备号和次设备号均为0
- 硬件开发笔记(十): 硬件开发基本流程,制作一个USB转RS232的模块(九):创建CH340G/MAX232封装库sop-16并关联原理图元器件
- How to write a resume that shines in front of another interviewer [easy to understand]
- Hangzhou Electric 3711 binary number
猜你喜欢

機器人(自動化)課程的持續學習-2022-

Five years of automated testing, and finally into the ByteDance, the annual salary of 30W is not out of reach

深耕开发者生态,加速AI产业创新发展 英特尔携众多合作伙伴共聚
![[team learning] [phase 34] Baidu PaddlePaddle AI talent Creation Camp](/img/eb/9aed3bbbd5b6ec044ec5542297f3c6.jpg)
[team learning] [phase 34] Baidu PaddlePaddle AI talent Creation Camp

Video fusion cloud platform easycvr video Plaza left column list style optimization

英特尔与信步科技共同打造机器视觉开发套件,协力推动工业智能化转型

Case reward: Intel brings many partners to promote the innovation and development of multi domain AI industry

Network Security Learning - Information Collection
![[coded font series] opendyslexic font](/img/5e/e1512ffe494b5d0e7d6d6765644126.png)
[coded font series] opendyslexic font

buildroot的根文件系统提示“depmod:applt not found”
随机推荐
Continuous learning of Robotics (Automation) - 2022-
浙江大学周亚金:“又破又立”的顶尖安全学者,好奇心驱动的行动派
Unit test asp Net MVC 4 Application - unit testing asp Net MVC 4 apps thoroughly
Ssm+jsp realizes enterprise management system (OA management system source code + database + document +ppt)
一图看懂!为什么学校教了你Coding但还是不会的原因...
ACL2022 | 分解的元学习小样本命名实体识别
[multi threading exercise] write a multi threading example of the producer consumer model.
两个div在同一行,两个div不换行「建议收藏」
视频融合云平台EasyCVR视频广场左侧栏列表样式优化
Intel and Xinbu technology jointly build a machine vision development kit to jointly promote the transformation of industrial intelligence
How to conduct website testing of software testing? Test strategy let's go!
How to write a resume that shines in front of another interviewer [easy to understand]
Data security -- 12 -- Analysis of privacy protection
How do test / development programmers get promoted? From nothing, from thin to thick
Lecture 3 of "prime mover x cloud native positive sounding, cost reduction and efficiency enhancement lecture" - kubernetes cluster utilization improvement practice
Mongo shell, the most complete mongodb in history
EasyCVR视频广场点击播放时,主菜单高亮效果消失问题的修复
[untitled]
高薪程序员&面试题精讲系列120之Redis集群原理你熟悉吗?如何保证Redis的高可用(上)?
Pyqt5 out of focus monitoring no operation timer