1 条题解

  • 0
    @ 2026-10-25 23:56:34

    思路与算法

    每次种树新增一种独立的树,保留它的区间 [l,r]。它与查询 [L,R] 相交,当且仅当 l≤R 且 r≥L。因此答案等于“左端点≤R的区间数”减去“右端点<L的区间数”。用两棵树状数组分别维护左端点与右端点的出现次数;插入时各做一次点加,查询时各取一次前缀和。

    正确性说明

    左端点大于 R 的区间不可能相交;剩下的区间中,只有右端点小于 L 的区间完全在查询左侧,需要排除。由于区间满足 l≤r,所有右端点<L的区间都已包含在左端点≤R的集合中,恰好减去一次,不会漏计或重复。

    复杂度

    时间 O(N+M log N),空间 O(N)。

    易错点

    一次种树对应一个种类,即使区间完全相同也要再次计数。不要把答案误写成覆盖长度或覆盖次数之和。闭区间在端点相等时仍然相交,所以右端点查询使用 L-1。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n, m;
        cin >> n >> m;
        vector<int> left(n + 1), right(n + 1);
        auto add = [&](vector<int> &t, int x) {
            for (; x <= n; x += x & -x)
                t[x]++;
        };
        auto sum = [&](vector<int> &t, int x) {
            int ans = 0;
            for (; x; x -= x & -x)
                ans += t[x];
            return ans;
        };
        while (m--) {
            int k, l, r;
            cin >> k >> l >> r;
            if (k == 1) {
                add(left, l);
                add(right, r);
            } else
                cout << sum(left, r) - sum(right, l - 1) << '\n';
        }
    }
    
    • 1

    信息

    ID
    1613
    时间
    1000ms
    内存
    512MiB
    难度
    普及
    标签
    递交数
    1
    已通过
    1
    上传者