珂朵莉树的map实现

1 引入

最近看jiangly的CF1638E代码,发现jiangly的珂朵莉树是用map实现的。于是研究学习了一下。

CF1638E jiangly代码

如果没有接触过珂朵莉树,请先学习下面的内容。

珂朵莉树原理及set实现

珂朵莉树的复杂度分析

CF1638E 珂朵莉树题解

2 珂朵莉树的map实现原理

珂朵莉树的set实现中,一个区间被记为 [ l , r , v a l ] [l, r, val] [l,r,val] ,分别表示区间左端点,区间右端点,和区间所储存的值。

但是,由于珂朵莉树的区间和区间时相邻的,本区间的右端点一定为下一个区间的左端点,所以我们可以将一个区间简单记为 [ l , v a l ] [l, val] [l,val] ,分别表示区间的左端点和区间所储存的值。

这样,我们就可以直接用标准库里map,对于一个区间,我们将 l l l 记为map里的key值,将 v a l val val 记为map里的value值。这样写起来更容易,代码量也更小。

3 珂朵莉树的map实现方法

先直接上完整代码。

struct ODT {
    const int n;
    map<int, int> mp;
    ODT(int n) : n(n) { mp[-1] = 0 }
    void split(int x) {
        auto it = prev(mp.upper_bound(x)); //找到左端点小于等于x的区间
        mp[x] = it->second; //设立新的区间,并将上一个区间储存的值复制给本区间。
    }
    void assign(int l, int r, int v) { // 注意,这里的r是区间右端点+1
        split(l);
        split(r);
        auto it = mp.find(l);
        while (it->first != r) {
            it = mp.erase(it);
        }
        mp[l] = v;
    }
    void update(int l, int r, int c) { // 其他操作
        split(l);
        split(r);
        auto it = mp.find(l);
        while (it->first != r) {
            // 根据题目需要做些什么
            it = next(it);
        }
    }
};

然后我们逐一进行讲解

3.1 初始化操作

设区间下标为 [ 0 , n − 1 ] [0, n - 1] [0,n1]
由于一开始只有一个区间,即 [ 0 , n − 1 ] [0, n - 1] [0,n1],那么我们初始化时,只用插入一个左端点为 0 0 0 的区间。

	ODT(int n) : n(n) { mp[-1] = 0 }

3.2 split操作

假设我们需要以 x x x 为左端点建立新区间,我们直接在map中找到左端点小于等于 x x x 的区间,设立新的区间,并将上一个区间储存的值复制给本区间。

	void split(int x) {
        auto it = prev(mp.upper_bound(x)); //找到左端点小于等于x的区间
        mp[x] = it->second; //设立新的区间,并将上一个区间储存的值复制给本区间。
    }

3.3 assign操作

对于assign操作,我们需要把 [ l , r − 1 ] [l, r-1] [l,r1]内所有区间左端点删除,再建立新的区间。

    void assign(int l, int r, int v) { // 注意,这里的r是区间右端点+1
        split(l);
        split(r);
        auto it = mp.find(l);
        while (it->first != r) {
            it = mp.erase(it);
        }
        mp[l] = v;
    }
};

3.4 其他操作

	void update(int l, int r, int c) { // 其他操作
        split(l);
        split(r);
        auto it = mp.find(l);
        while (it->first != r) {
            // 根据题目需要做些什么
            it = next(it);
        }
    }

4 CF1638E的珂朵莉树实现代码

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using ldb = long double;
#define int i64
#define double ldb

template <typename T>
struct BIT {
    const int n;
    std::vector<T> a;
    BIT(int n) : n(n), a(n) {}
    void add(int x, T v) {
        for (int i = x + 1; i <= n; i += i & -i) {
            a[i - 1] += v;
        }
    }
    void rangeAdd(int l, int r, T v) {
        add(l, v);
        add(r, -v);
    }
    T sum(int x) {
        T ans = 0;
        for (int i = x + 1; i > 0; i -= i & -i) {
            ans += a[i - 1];
        }
        return ans;
    }
    T rangeSum(int l, int r) {
        return sum(r) - sum(l);
    }
};

struct ODT {
    const int n;
    map<int, int> mp;
    vector<int> lazy;
    BIT<int> bit;
    ODT(int n) : n(n), lazy(n), bit(n) { mp[-1] = 0; }
    void split(int x) {
        auto it = prev(mp.upper_bound(x));
        mp[x] = it->second;
    }
    void assign(int l, int r, int v) {
        split(l);
        split(r);
        auto it = mp.find(l);
        while (it->first != r) {
            it = mp.erase(it);
        }
        mp[l] = v;
    }
    void update(int l, int r, int c) {
        split(l);
        split(r);
        auto it = mp.find(l);
        while (it->first != r) {
            bit.rangeAdd(it->first, next(it)->first, lazy[it->second] - lazy[c]);
            it = next(it);
        }
    }
    void add(int c, int x) {
        lazy[c] += x;
    }
    int query(int x) {
        split(x);
        return bit.sum(x) + lazy[mp[x]];
    }
};

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, q;
    cin >> n >> q;

    ODT odt(n);

    for (int i = 0; i < q; i++) {
        string op;
        cin >> op;
        if (op == "Color") {
            int l, r, c;
            cin >> l >> r >> c;
            l--;
            c--;

            odt.update(l, r, c);
            odt.assign(l, r, c);
        }
        else if (op == "Add") {
            int c, x;
            cin >> c >> x;
            c--;

            odt.add(c, x);
        }
        else if (op == "Query") {
            int x;
            cin >> x;
            x--;

            cout << odt.query(x) << "\n";
        }
    }
    return 0;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值