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;
};