当前位置:网站首页>【线段树实战】最近的请求次数 + 区域和检索 - 数组可修改+我的日程安排表Ⅰ/Ⅲ
【线段树实战】最近的请求次数 + 区域和检索 - 数组可修改+我的日程安排表Ⅰ/Ⅲ
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;
}
}
边栏推荐
- EasyCVR集群版本添加RTSP设备提示服务器ID错误,该如何解决?
- 硬件开发笔记(十): 硬件开发基本流程,制作一个USB转RS232的模块(九):创建CH340G/MAX232封装库sop-16并关联原理图元器件
- 各路行业大佬称赞的跨架构开发“神器”,你get同款了吗?
- VM virtual machine operating system not found and NTLDR is missing
- What is CGI, IIS, and VPS "suggested collection"
- Kivy tutorial of setting the size and background of the form (tutorial includes source code)
- ESG Global Leaders Summit | Intel Wang Rui: coping with global climate challenges with the power of science and technology
- Surpassing postman, the new generation of domestic debugging tool apifox is elegant enough to use
- ACL2022 | 分解的元学习小样本命名实体识别
- 过气光刻机也不能卖给中国!美国无理施压荷兰ASML,国产芯片再遭打压
猜你喜欢
Optimization of channel status offline of other server devices caused by easycvr cluster restart
AI landing new question type RPA + AI =?
Win11远程桌面连接怎么打开?Win11远程桌面连接的五种方法
[knife-4j quickly build swagger]
EasyCVR集群版本添加RTSP设备提示服务器ID错误,该如何解决?
The root file system of buildreoot prompts "depmod:applt not found"
EasyCVR集群重启导致其他服务器设备通道状态离线情况的优化
SSM+jsp实现仓库管理系统,界面那叫一个优雅
Break the memory wall with CPU scheme? Learn from PayPal to expand the capacity of aoteng, and the volume of missed fraud transactions can be reduced to 1/30
用CPU方案打破内存墙?学PayPal堆傲腾扩容量,漏查欺诈交易量可降至1/30
随机推荐
Antd comment recursive loop comment
Restore backup data on GCS with br
[untitled]
Redis source code learning (31), dictionary learning, dict.c (1)
微信能开小号了,拼多多“砍一刀”被判侵权,字节VR设备出货量全球第二,今日更多大新闻在此
AI表现越差,获得奖金越高?纽约大学博士拿出百万重金,悬赏让大模型表现差劲的任务
Unit test asp Net MVC 4 Application - unit testing asp Net MVC 4 apps thoroughly
[coded font series] opendyslexic font
接口自动化测试实践指导(中):接口测试场景有哪些
Video fusion cloud platform easycvr video Plaza left column list style optimization
Deeply cultivate the developer ecosystem, accelerate the innovation and development of AI industry, and Intel brings many partners together
Five years of automated testing, and finally into the ByteDance, the annual salary of 30W is not out of reach
Use dumping to back up tidb cluster data to GCS
Intel David tuhy: the reason for the success of Intel aoten Technology
数学分析_笔记_第10章:含参变量积分
Surpassing postman, the new generation of domestic debugging tool apifox is elegant enough to use
Win11控制面板快捷键 Win11打开控制面板的多种方法
EasyCVR无法使用WebRTC进行播放,该如何解决?
[on automation experience] the growth path of automated testing
[leetcode]Spiral Matrix II