更新数组后处理求和查询

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

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

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

1. 线段树 + 懒标记

线段树用于区间修改和区间求和

class Solution {
    struct TreeNode {
        int left; // 节点区间左边界
        int right; // 节点区间右边界
        int value; // 节点存储的信息,这里存储区间和
        bool lazytag;//懒标记,不用每次修改区间,都去修改全部节点
    };
public:
    int n;
    vector<TreeNode> tree;

     void build(int index, int left, int right, const vector<int> &arr) {//初始化
        tree[index].left = left;
        tree[index].right = right;
        tree[index].lazytag = false;
        if (left == right) {
            tree[index].value = arr[left];
            return;
        } 
        int mid = (left + right) / 2;
        build(index * 2 + 1, left, mid, arr);//递归建左树,左节点对应左区间
        build(index * 2 + 2, mid + 1, right, arr);//递归建右树,右节点对应右区间
        tree[index].value = tree[index*2+1].value + tree[index*2+2].value;
    }

    int query(int index, int left, int right) {//查询
        if (tree[index].left == left && tree[index].right == right) 
            return tree[index].value;
        pushdown(index);//将查询区间的值进行更新
        int mid = (tree[index].left + tree[index].right) / 2;
        if (right <= mid) 
            return query(index * 2 + 1, left, mid);
        else if (left > mid) 
            return query(index * 2 + 2, mid+1, right);
        else 
            return query(index * 2 + 1, left, mid) + query(index * 2 + 2, mid+1, right);
    }

    void modify(int index, int left, int right) {
        if (tree[index].left >= left && tree[index].right <= right) {//修改区间囊括当前节点
            tree[index].value = (tree[index].right - tree[index].left + 1) - tree[index].value; //进行翻转,区间长度减去当前和
            tree[index].lazytag = !tree[index].lazytag; //同时翻转懒标记
            return;
        }
        pushdown(index);
        int mid = (tree[index].left + tree[index].right) / 2;
        if (right <= mid) 
            modify(index*2 + 1, left, right);
        else if (left > mid) 
            modify(index*2 + 2, left, right);
        else{
            modify(index*2 + 1, left, right);
            modify(index*2 + 2, left, right);
        }
        tree[index].value = tree[index*2 + 1].value + tree[index*2 + 2].value;
    }

    void pushdown(int index) {
        if(tree[index].lazytag) {//该区间需要修改
            tree[2*index+1].lazytag = !tree[2*index+1].lazytag;
            tree[2*index+1].value = tree[2*index+1].right - tree[2*index+1].left + 1 - tree[2*index+1].value;
            tree[2*index+2].lazytag = !tree[2*index+2].lazytag;
            tree[2*index+2].value = tree[2*index+2].right - tree[2*index+2].left + 1 - tree[2*index+2].value;
            tree[index].lazytag = false;
        }
    }

    vector<long long> handleQuery(vector<int>& nums1, vector<int>& nums2, vector<vector<int>>& queries) {
        //初始化线段树
        n = nums1.size();
        tree.resize(4*n);
        build(0,0,n-1,nums1);

        long long sum = accumulate(nums2.begin(), nums2.end(), 0LL);
        vector<long long> ans;
        for (int i = 0; i < queries.size(); i++) {
            if (queries[i][0] == 1) {
                int l = queries[i][1]; //左边界
                int r = queries[i][2]; //右边界
                modify(0, l, r); //翻转
            } else if (queries[i][0] == 2) {
                sum += (long long)query(0, 0, n - 1) * queries[i][1]; //统计1的个数,直接叠加到结果
            } else if (queries[i][0] == 3) {
                ans.emplace_back(sum);
            }
        }
        return ans;
    }
};

posted @ 2023-07-27 03:12  失控D大白兔  阅读(4)  评论(0编辑  收藏  举报