\(\text{Solution}\)
二维平面很容易想到扫描线,然后不知道维护什么信息
颜色的变化自然要能记录下来,所以线段树每个结点维护一个 set
表示覆盖这个点代表区间的所有颜色
这样加入和删除就容易了
统计答案,无非是把当前能看到且未被统计过的颜色统计入答案
考虑一个颜色怎样合法,必然是存在一条从根到叶结点的路径使得这条路径上颜色的最大值是这个颜色
那么就维护当前能看到且未被统计过的颜色的最大值,取出最大值,标记为统计过,不断重复这样的过程,直到没有可以看到的颜色
最大值的维护要注意到是能看到的,一些统计过的且还在线段树上的颜色可能盖住别的颜色
具体来讲就是:子树传上来的能看到且未被统计过的颜色可能被当前结点的颜色(已统计过)覆盖导致不可见
或者当前结点的颜色(未被统计过)被子树已统计过的颜色覆盖导致不可见,所以要额外维护一个变量,具体见代码
\(\texttt{warning:}\) 线段的离散化直接离散化,不要先把边区间变成点的闭区间,不然会少掉一些必要的位置,如边区间 \(\text{[1,4],[1,2],[3,4]}\) 会错。
同理:点的闭区间离散化先变成左闭右开区间
不过影响因题而异,这题影响显著
\(\text{Code}\)
#include <bits/stdc++.h>
#define eb emplace_back
#define IN inline
using namespace std;
template <typename Tp>
IN void read(Tp &x) {
x = 0; char ch = getchar(); int f = 0;
for(; !isdigit(ch); f = (ch == '-' ? 1 : f), ch = getchar());
for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar());
if (f) x = ~x + 1;
}
const int N = 2e5 + 5;
int n, lsx[N], lsy[N], used[N];
struct Rect{int x0, y0, x1, y1;}a[N];
struct node{int id, v;};
vector<node> G[N];
struct SegmentTree {
#define ls (p << 1)
#define rs (ls | 1)
#define mid (l + r >> 1)
set<int> seg[N << 2]; int mx[N << 2], mn[N << 2];
void pushup(int p, int fl) {
if (fl) mx[p] = mn[p] = 0; else mx[p] = max(mx[ls], mx[rs]), mn[p] = min(mn[ls], mn[rs]);
if (seg[p].size()) {
int k = *(--seg[p].end());
if (used[k]) mn[p] = max(mn[p], k); else mx[p] = max(mx[p], k);
}
mx[p] = (mn[p] > mx[p] ? 0 : mx[p]);
}
void update(int p, int l, int r, int x, int y, int z, int v) {
if (x > r || y < l) return;
if (x <= l && r <= y) {
if (v == 1) seg[p].insert(z); else if (v == -1) seg[p].erase(z);
return pushup(p, l == r), void();
}
update(ls, l, mid, x, y, z, v), update(rs, mid + 1, r, x, y, z, v), pushup(p, l == r);
}
}T;
int main() {
read(n); int totx = 0, toty = 0;
for(int i = 1, x0, y0, x1, y1; i <= n; i++) {
read(x0), read(y0), read(x1), read(y1), a[i] = Rect{x0, y0, x1, y1};
lsx[++totx] = x0, lsx[++totx] = x1, lsy[++toty] = y0, lsy[++toty] = y1;
}
sort(lsx + 1, lsx + totx + 1), totx = unique(lsx + 1, lsx + totx + 1) - lsx - 1;
sort(lsy + 1, lsy + toty + 1), toty = unique(lsy + 1, lsy + toty + 1) - lsy - 1;
for(int i = 1, x0, x1, y0, y1; i <= n; i++) {
x0 = lower_bound(lsx + 1, lsx + totx + 1, a[i].x0) - lsx;
x1 = lower_bound(lsx + 1, lsx + totx + 1, a[i].x1) - lsx;
y0 = lower_bound(lsy + 1, lsy + toty + 1, a[i].y0) - lsy;
y1 = lower_bound(lsy + 1, lsy + toty + 1, a[i].y1) - lsy;
a[i] = Rect{x0, y0, x1, y1}, G[x0].eb(node{i, 1}), G[x1].eb(node{i, -1});
}
int ans = 1;
for(int i = 1; i <= totx; i++) {
for(auto k : G[i]) T.update(1, 1, toty - 1, a[k.id].y0, a[k.id].y1 - 1, k.id, k.v);
while (T.mx[1])
++ans, used[T.mx[1]] = 1, T.update(1, 1, toty - 1, a[T.mx[1]].y0, a[T.mx[1]].y1 - 1, 0, 0);
}
printf("%d\n", ans);
}