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;
}
本文来自一名高中生,作者:To_Carpe_Diem

浙公网安备 33010602011771号