当前位置:网站首页>【线段树实战】最近的请求次数 + 区域和检索 - 数组可修改+我的日程安排表Ⅰ/Ⅲ
【线段树实战】最近的请求次数 + 区域和检索 - 数组可修改+我的日程安排表Ⅰ/Ⅲ
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;
}
}
边栏推荐
- kivy教程之设置窗体大小和背景(教程含源码)
- Both primary and secondary equipment numbers are 0
- Common methods of list and map
- Video fusion cloud platform easycvr video Plaza left column list style optimization
- leetcode 53. Maximum Subarray 最大子数组和(中等)
- Network Security Learning - Information Collection
- Unit test asp Net MVC 4 Application - unit testing asp Net MVC 4 apps thoroughly
- 科兴与香港大学临床试验中心研究团队和香港港怡医院合作,在中国香港启动奥密克戎特异性灭活疫苗加强剂临床试验
- EasyCVR视频广场点击播放时,主菜单高亮效果消失问题的修复
- 两个div在同一行,两个div不换行「建议收藏」
猜你喜欢
What about the collapse of win11 playing pubg? Solution to win11 Jedi survival crash
英特尔与信步科技共同打造机器视觉开发套件,协力推动工业智能化转型
接口自动化测试实践指导(中):接口测试场景有哪些
MySQL data loss, analyze binlog log file
[team learning] [phase 34] Baidu PaddlePaddle AI talent Creation Camp
Intel David tuhy: the reason for the success of Intel aoten Technology
C # use Siemens S7 protocol to read and write PLC DB block
数学分析_笔记_第10章:含参变量积分
深耕开发者生态,加速AI产业创新发展 英特尔携众多合作伙伴共聚
EasyCVR平台接入RTMP协议,接口调用提示获取录像错误该如何解决?
随机推荐
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
Intel David tuhy: the reason for the success of Intel aoten Technology
GPT-3当一作自己研究自己,已投稿,在线蹲一个同行评议
英特尔David Tuhy:英特尔傲腾技术成功的原因
Lecture 3 of "prime mover x cloud native positive sounding, cost reduction and efficiency enhancement lecture" - kubernetes cluster utilization improvement practice
Food Chem | in depth learning accurately predicts food categories and nutritional components based on ingredient statements
kivy教程之设置窗体大小和背景(教程含源码)
[leetcode]Spiral Matrix II
2022 middle school Youth Cup mathematical modeling question B fertility policy research ideas under the background of open three children
Win11远程桌面连接怎么打开?Win11远程桌面连接的五种方法
Win11 control panel shortcut key win11 multiple methods to open the control panel
Intel and Xinbu technology jointly build a machine vision development kit to jointly promote the transformation of industrial intelligence
Analysis on urban transportation ideas of 2022 Zhongqing cup C
NanopiNEO使用开发过程记录
Hangzhou Electric 3711 binary number
视频融合云平台EasyCVR视频广场左侧栏列表样式优化
Ssm+jsp realizes enterprise management system (OA management system source code + database + document +ppt)
EasyCVR集群重启导致其他服务器设备通道状态离线情况的优化
深耕开发者生态,加速AI产业创新发展 英特尔携众多合作伙伴共聚
主设备号和次设备号均为0