珂朵莉树与动态开点线段树

LeetCode699. 掉落的方块

珂朵莉树

class ChthollyTree
{
public:
    struct ChthollyNode
    {
        int left, right;
        mutable int value; // 可以直接在set里更改
        ChthollyNode(int l, int r = 0, int v = 0) : left(l), right(r), value(v) {}
        bool operator< (const ChthollyNode& n) const {
            return left < n.left;
        }
    };

    ChthollyTree(int minleft, int maxright) : m_set{{minleft, maxright}} {}

    auto split(int pos) {
        auto it = m_set.lower_bound(pos);
        if (it != m_set.end() && it->left == pos) return it;
        it--;
        auto left = it->left, right = it->right, value = it->value;
        // delete cur interval
        m_set.erase(it);
        // add [left, pos - 1]
        m_set.emplace(left, pos - 1, value);
        return m_set.emplace(pos, right, value).first;
    }
    // 对 [left, right] 区间赋值
    void assign(int left, int right, int value) {
        // 先右后左, 否则split右端点的时候可能会使左端点的迭代器失效
        auto itR = split(right + 1);
        auto itL = split(left);
        // 可以遍历区间[itL, itR)做一些计算
        m_set.erase(itL, itR); // 删除[itL, itR)
        m_set.emplace(left, right, value);
    }

private:
    std::set<ChthollyNode> m_set;
};

动态开点线段树

指针表示的动态开点线段树

class DSegmentTree
{
public:
    struct Node
    {
        int left, right; // [left, right]
        int value;
        int lazy;
        std::unique_ptr<Node> leftNode, rightNode;

        Node(int l, int r) : left(l), right(r), value(0), lazy(0) {}
    };
    
    DSegmentTree(int minleft, int maxright) : m_root(new Node(minleft, maxright)) {

    }

    void modify(int left, int right, int value) {
        modify(left, right, value, m_root.get());
    }

    int query(int left, int right) {
        return query(left, right, m_root.get());
    }

private:
    void modify(int left, int right, int value, Node* node) {
        // case1. 不在范围内
        if (node->left > right || node->right < left) return;
        // case2. 修改区间包含当前节点
        if (left <= node->left && node->right <= right) {
            node->value += value;
            node->lazy += value;
            return;
        }
        // case3. 相交
        // 动态开点并下传lazy
        pushdown(node);
        // 修改左右子树
        modify(left, right, value, node->leftNode.get());
        modify(left, right, value, node->rightNode.get());
        // 上传结果
        pushup(node);
    }

    int query(int left, int right, Node* node) {
        // case1. 不在范围内
        if (node->left > right || node->right < left) return 0;
        // case2. 区间包含当前节点
        if (left <= node->left && node->right <= right) {
            return node->value;
        }
        // case3. 相交
        // 动态开点并下传lazy
        pushdown(node);
        // 调查左右子树,此处依据实际场景变化
        int ans = 0;
        ans = std::max(ans, query(left, right, node->leftNode.get()));
        ans = std::max(ans, query(left, right, node->rightNode.get()));
        return ans;
    }

    void pushdown(Node* node) {
        // 动态开点
        int mid = node->left + (node->right - node->left) / 2;
        if (node->leftNode == nullptr) {
            node->leftNode = std::make_unique<Node>(node->left, mid);
        }
        if (node->rightNode == nullptr) {
            node->rightNode = std::make_unique<Node>(mid + 1, node->right);
        }
        // 懒标记
        if (node->lazy > 0) {
            node->leftNode->value += node->lazy;
            node->rightNode->value += node->lazy;
            node->leftNode->lazy += node->lazy;
            node->rightNode->lazy += node->lazy;
            node->lazy = 0;
        }
    }

    void pushup(Node* node) {
        node->value = std::max(node->leftNode->value, node->rightNode->value);
    }

    std::unique_ptr<Node> m_root;
};

哈希表表示的动态开点线段树

class DSegmentTree
{
public:
    struct Node
    {
        int left, right; // [left, right]
        int value;
        int lazy;

        Node() : left(0), right(INT_MAX), value(0), lazy(0) {}
        Node(int l, int r) : left(l), right(r), value(0), lazy(0) {}
    };

    DSegmentTree(int minleft, int maxright) : m_root(0) {
        m_nodeMap[m_root] = Node(minleft, maxright);
    }

    void modify(int left, int right, int value) {
        modify(left, right, value, m_root);
    }

    int query(int left, int right) {
        return query(left, right, m_root);
    }

private:
    void modify(int left, int right, int value, int index) {
        auto& node = m_nodeMap[index];
        // case1. 不在范围内
        if (node.left > right || node.right < left) return;
        // case2. 修改区间包含当前节点
        if (left <= node.left && node.right <= right) {
            node.value = value;
            node.lazy = value;
            return;
        }
        // case3. 相交
        // 动态开点并下传lazy
        pushdown(index);
        // 修改左右子树
        modify(left, right, value, 2 * index + 1);
        modify(left, right, value, 2 * index + 2);
        // 上传结果
        pushup(index);
    }

    int query(int left, int right, int index) {
        // case1. 不在范围内
        auto& node = m_nodeMap[index];
        if (node.left > right || node.right < left) return 0;
        // case2. 区间包含当前节点
        if (left <= node.left && node.right <= right) {
            return node.value;
        }
        // case3. 相交
        // 动态开点并下传lazy
        pushdown(index);
        // 调查左右子树,此处依据实际场景变化
        int ans = 0;
        ans = std::max(ans, query(left, right, 2 * index + 1));
        ans = std::max(ans, query(left, right, 2 * index + 2));
        return ans;
    }

    void pushdown(int index) {
        auto& node = m_nodeMap[index];
        // 动态开点
        int mid = node.left + (node.right - node.left) / 2;
        if (!m_nodeMap.count(2 * index + 1)) {
            m_nodeMap[2 * index + 1] = Node(node.left, mid);
        }
        if (!m_nodeMap.count(2 * index + 2)) {
            m_nodeMap[2 * index + 2] = Node(mid + 1, node.right);
        }
        // 懒标记
        if (node.lazy > 0) {
            auto& leftNode = m_nodeMap[2 * index + 1];
            auto& rightNode = m_nodeMap[2 * index + 2];
            leftNode.value = node.lazy;
            rightNode.value = node.lazy;
            leftNode.lazy = node.lazy;
            rightNode.lazy = node.lazy;
            node.lazy = 0;
        }
    }

    void pushup(int index) {
        auto& node = m_nodeMap[index];
        node.value = std::max(m_nodeMap[2 * index + 1].value, m_nodeMap[2 * index + 2].value);
    }

    int m_root;
    std::unordered_map<int, Node> m_nodeMap;
};
posted @ 2022-05-26 10:38  miyanyan  阅读(27)  评论(0编辑  收藏  举报