P3740 [HAOI2014] 贴海报

P3740 [HAOI2014] 贴海报

大意

每次用一个新数覆盖一段区间,最后问区间上有几种不同的数字。

思路

首先考虑用线段树做。

发现数据范围很大,但是实则不需要考虑啊,因为我们的海报的数量一定,可以考虑离散化去重,然后用线段树做。

每次更改一段区间的话,采用标记延迟下传的方式,如果在目标区间就先打上懒标记,如果以后访问到了再下传,这样就不必要每次放到叶子上了。

最终查询就直接访问所有叶子就好,用个 set 去重海报。

代码

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

const int N = 1e6 + 10;

int a[N], lazy[N], n, c;

set<int> cnt;

void update(int rt, int l, int r, int L, int R, int x) {
    if (L > r || R < l) return;
    if (L <= l && r <= R) {
        lazy[rt] = x;
        a[rt] = x;
        return;
    }
    int mid = (l + r) / 2;
    if (lazy[rt]) {
        lazy[rt * 2] = lazy[rt * 2 + 1] = lazy[rt];
        a[rt * 2] = a[rt * 2 + 1] = lazy[rt];
        lazy[rt] = 0;
    }
    update(rt * 2, l, mid, L, R, x);
    update(rt * 2 + 1, mid + 1, r, L, R, x);
}

void query(int rt, int l, int r) {
    if (l == r) {
        if (a[rt]) cnt.insert(a[rt]);
        return;
    }
    int mid = (l + r) / 2;
    if (lazy[rt]) {
        lazy[rt * 2] = lazy[rt * 2 + 1] = lazy[rt];
        a[rt * 2] = a[rt * 2 + 1] = lazy[rt];
        lazy[rt] = 0;
    }
    query(rt * 2, l, mid);
    query(rt * 2 + 1, mid + 1, r);
}

int l[N], r[N];

int main() {
    int c;
        cin >> c >> n;
        memset(a, 0, sizeof(a));
        memset(lazy, 0, sizeof(lazy));
        set<int> uniq;
        map<int, int> d;
        for (int i = 1; i <= n; i++) {
            cin >> l[i] >> r[i];
            uniq.insert(l[i]);
            uniq.insert(r[i]);
            uniq.insert(l[i] - 1);
            uniq.insert(r[i] + 1);
        }
        int now = 0;
        for (auto x: uniq) {
            d[x] = ++ now;
        }
        for (int i = 1; i <= n; i++) {
            l[i] = d[l[i]];
            r[i] = d[r[i]];
            update(1, 1, now, l[i], r[i], i);
        }
        cnt.clear();
        query(1, 1, now);
        cout << cnt.size() << endl;

    return 0;
}
posted @ 2025-12-12 21:44  To_Carpe_Diem  阅读(4)  评论(0)    收藏  举报