【每日一题Day277】LC2569更新数组后处理求和查询 | 线段树

简介: 【每日一题Day277】LC2569更新数组后处理求和查询 | 线段树

更新数组后处理求和查询【LC2569】

给你两个下标从 0 开始的数组 nums1nums2 ,和一个二维数组queries 表示一些操作。总共有 3 种类型的操作:

  1. 操作类型 1 为 queries[i] = [1, l, r] 。你需要将 nums1 从下标 l 到下标 r 的所有 0 反转成 1 或将 1 反转成 0lr 下标都从 0 开始。
  2. 操作类型 2 为 queries[i] = [2, p, 0] 。对于 0 <= i < n 中的所有下标,令 nums2[i] = nums2[i] + nums1[i] * p
  3. 操作类型 3 为 queries[i] = [3, 0, 0] 。求 nums2 中所有元素的和。

请你返回一个数组,包含所有第三种操作类型的答案。

欠下的债还是要还的,终于把线段树板子搞好了

  • 思路

image.png

class Solution {
    public long[] handleQuery(int[] nums1, int[] nums2, int[][] queries) {
        List<Long> res = new ArrayList<>();
        int n = nums1.length;
        long sum2 = 0L;
        for (int i = 0; i < n; i++){
            sum2 += nums2[i];
        }
        SegmentTree seg = new SegmentTree(nums1);
        for (int[] q : queries){
            if (q[0] == 1){
                seg.updateAll(1, q[1] + 1, q[2] + 1);
            }else if (q[0] == 2){
                sum2 += 1L * q[1] * seg.query(1, 1, nums2.length);// 处理越界
            }else{
                res.add(sum2);
            }
        }
        return res.stream().mapToLong(x -> x).toArray();
    }
}
class Node {
    int l, r;
    int sum;// 和 题目所要求的值
    int lazy;// 延迟修改的值
}
class SegmentTree {
    private Node[] tr;// 线段树
    private int[] nums;// 原数组
    public SegmentTree(int[] nums) {
        int n = nums.length;
        this.nums = nums;
        tr = new Node[n << 2];
        for (int i = 0; i < tr.length; ++i) {
            tr[i] = new Node();
        }
        build(1, 1, n);// 建树
    }
    private void build(int u, int l, int r) {// l,r表示当前区间 u表示当前节点编号(1,n)
        tr[u].l = l;
        tr[u].r = r;
        if (l == r) {// 若到达叶子节点
            tr[u].sum = nums[l - 1];// 存储值
            return;
        }
        // 左右递归
        int mid = (l + r) >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
        pushup(u);// 更新信息
    }
  // 区间查询
    public int query(int u, int l, int r) {
         if (tr[u].l >= l && tr[u].r <= r) {
             // 在区间内,直接返回 
            return tr[u].sum;
        }
        pushdown(u);
        int res = 0;
        int mid = (tr[u].l + tr[u].r) >> 1;
        if (l <= mid) {
            res += query(u << 1, l, mid);
        }
        if (r > mid) {
            res += query(u << 1 | 1, mid + 1, r);
        }
        return res;
    }
    // 区间修改:
    public void updateAll(int u, int l, int r) {
        if (tr[u].l >= l && tr[u].r <= r) {
            tr[u].lazy ^= 1;
            tr[u].sum = tr[u].r - tr[u].l + 1 - tr[u].sum ;
            return;
        }
        // 在回溯之前向下传递修改标记
        pushdown(u);
        int mid = (tr[u].l + tr[u].r) >> 1;
        if (l <= mid) {
            updateAll(u << 1, l, r);
        }
        if (r > mid) {
            updateAll(u << 1 | 1, l, r);
        }
        pushup(u);// 更新本节点信息
    }
    // pushUp函数更新节点信息, 本题是求和
    private void pushup(int u) {
        tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
    }
    // 懒加载
    private void pushdown(int u) {
      if (tr[u].lazy == 1) {// 如果懒标记不为0,就将其下传,修改左右儿子维护的值
            f(u << 1);
            f(u << 1 | 1);
            tr[u].lazy = 0;// 向下传之后将该节点的懒标记清0
      }
    }
    // 父节点修改时,维护子节点的更新
    private void f(int u){
        tr[u].sum = tr[u].r - tr[u].l + 1 - tr[u].sum;
        tr[u].lazy ^= 1;// 修改两次即为不修改
    }
}

image.png

目录
打赏
0
0
0
0
5
分享
相关文章
|
9月前
|
【每日一题Day307】LC56合并区间 | 排序
【每日一题Day307】LC56合并区间 | 排序
51 0
|
9月前
【每日一题Day215】LC1090受标签影响的最大值 | 贪心+排序+哈希表
【每日一题Day215】LC1090受标签影响的最大值 | 贪心+排序+哈希表
54 0
|
9月前
2569. 更新数组后处理求和查询(模板 + 普通线段树熟练掌握)
2569. 更新数组后处理求和查询(模板 + 普通线段树熟练掌握)
【每日一题Day108】LC1798你能构造出连续值的最大数目 | 贪心
局部最优:每次从数组中找到未选择数字中的最小值来更新区间,如果当前连续值x小于选择的数值coin,那么无法获得更大的区间,退出循环
62 0
【每日一题Day128】LC2357使数组中所有元素都等于零 | 排序+模拟 哈希表
【每日一题Day128】LC2357使数组中所有元素都等于零 | 排序+模拟 哈希表
37 0
|
9月前
|
【每日一题Day132】LC23633合并相似的物品 | 哈希表 排序+双指针
【每日一题Day132】LC23633合并相似的物品 | 哈希表 排序+双指针
64 0
【每日一题Day69】转换字符串的最少操作次数 |贪心
实现:遍历整个字符串,如果当前字符为’X’,那么进行转换,指针后移三位;如果当前字符为’O’,那么指针后移一位
94 0
|
9月前
【每日一题Day118】LC1124表现良好的最长时间段 | 前缀和+单调栈/哈希表
【每日一题Day118】LC1124表现良好的最长时间段 | 前缀和+单调栈/哈希表
64 0
【每日一题Day66】LC1754构造字典序最大的合并字符串 | 贪心 双指针模拟
思路:双指针遍历两个字符串,贪心比较字符的字典顺序,并添加至结果集
85 0
【每日一题Day66】LC1754构造字典序最大的合并字符串 | 贪心 双指针模拟

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等