这篇文章写得挺好:https://blog.csdn.net/Tiw_Air_Op1721/article/details/84038246
但是关于mn的作用没写全-。-
D. Arkady and Rectangles
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Arkady has got an infinite plane painted in color 00. Then he draws ?n rectangles filled with paint with sides parallel to the Cartesian coordinate axes, one after another. The color of the ?i-th rectangle is ?i (rectangles are enumerated from 11 to ?n in the order he draws them). It is possible that new rectangles cover some of the previous ones completely or partially.
Count the number of different colors on the plane after Arkady draws all the rectangles.
Input
The first line contains a single integer ?n (1≤?≤1000001≤n≤100000) — the number of rectangles.
The ?i-th of the next ?n lines contains 44 integers ?1x1, ?1y1, ?2x2 and ?2y2 (−109≤?1<?2≤109−109≤x1<x2≤109, −109≤?1<?2≤109−109≤y1<y2≤109) — the coordinates of corners of the ?i-th rectangle.
Output
In the single line print the number of different colors in the plane, including color 00.
Examples
input
Copy
5
-1 -1 1 1
-4 0 0 4
0 0 4 4
-4 -4 0 0
0 -4 4 0
output
Copy
5
input
Copy
4
0 0 4 4
-4 -4 0 0
0 -4 4 0
-2 -4 2 4
output
Copy
5
Note
That's how the plane looks in the first sample
That's how the plane looks in the second sample
00 = white, 11 = cyan, 22 = blue, 33 = purple, 44 = yellow, 55 = red.
中文题意:
就是给你一些颜色各不相同的方块,问能看到几种颜色(包括空白)
官方题解-。-
#include <bits/stdc++.h>
using namespace std;
const int SZ = 1500500;
const int N = 100500;
int x1[N], x2[N], yy1[N], y2[N];
bool erased[N];
priority_queue<int> els[SZ];
int mn[SZ];
int mx[SZ];
int n;
bool seen[N];
enum {
ACTION_ADD,
ACTION_ERASE,
ACTION_VOID
};
void recalc(int cur) {
//我们定义 mx 表示 Maximal visible color in subtree
//我们再给每个区间定义 mn 表示 Minimal visible color in subtree
int max_in_child = max(mx[cur * 2], mx[cur * 2 + 1]);
while (!els[cur].empty() && erased[els[cur].top()]) {
els[cur].pop();
}
//max_in_vertex是能覆盖当前节点表示区间的所有颜色中的最大编号
int max_in_vertex = els[cur].empty() ? -1 : els[cur].top();
int min_in_child = min(mn[cur * 2], mn[cur * 2 + 1]);
//如果区间被一种颜色覆盖
if (max_in_vertex > max_in_child) {
//如果能完全覆盖左右儿子的颜色(可以不同)的编号 全部比 max_in_vertex大
//说明cur节点表示的区间会被多种颜色覆盖
/*
max_in_vertex = 0 min_in_child = 1 max_in_child = -1
max_in_vertex = 0 min_in_child = 2 max_in_child = -1
max_in_vertex = 6 min_in_child = 8 max_in_child = -1
max_in_vertex = 53 min_in_child = 278 max_in_child = -1
max_in_vertex = 182 min_in_child = 278 max_in_child = -1
max_in_vertex = 26 min_in_child = 83 max_in_child = -1
max_in_vertex = 26 min_in_child = 83 max_in_child = -1
max_in_vertex = 26 min_in_child = 83 max_in_child = -1
max_in_vertex = 26 min_in_child = 83 max_in_child = -1
max_in_vertex = 627 min_in_child = 635 max_in_child = -1
max_in_vertex = 26 min_in_child = 83 max_in_child = -1
max_in_vertex = 26 min_in_child = 83 max_in_child = -1
*/
// max_in_vertex 既然已经比 max_in_child 大了,怎么会比 min_in_child 小呢?见上面数据
// 因为 max_in_child = -1, 也就是child的颜色被选光了
// 然后child之前选过的颜色把这个 max_in_vertex 的颜色覆盖了-。-
if (seen[max_in_vertex] || max_in_vertex < min_in_child) {
mx[cur] = -1;
}
else {
mx[cur] = max_in_vertex;
}
}
else {
mx[cur] = max_in_child;
}
mn[cur] = max(max_in_vertex, min_in_child);
}
void update(int cur, int lb, int rb, int id, int action, int l = 0, int r = 2 * N) {
if (lb >= r || rb <= l) {
return;
}
if (lb <= l && rb >= r) {
if (action == ACTION_ADD) {
//els存的是所有能覆盖编号为cur的树的方块编号
els[cur].push(id);
}
recalc(cur);
return;
}
int mid = (l + r) / 2;
update(cur * 2, lb, rb, id, action, l, mid);
update(cur * 2 + 1, lb, rb, id, action, mid, r);
recalc(cur);
}
set<int> cx, cy;
unordered_map<int, int> id_x, id_y;
vector<pair<int, int> > events[2 * N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cout.precision(15);
cin >> n;
for (int i = 0; i < n; i++) {
cin >> x1[i] >> yy1[i] >> x2[i] >> y2[i];
cx.insert(x1[i]);
cx.insert(x2[i]);
cy.insert(yy1[i]);
cy.insert(y2[i]);
}
int j = 0;
//id_x[a] 是横坐标a的编号。所有横坐标从小到大排序后依次赋予0, 1, 2, .., n号
for (auto x : cx) {
id_x[x] = j++;
}
j = 0;
for (auto y : cy) {
id_y[y] = j++;
}
//x1[i]现在存的是编号为i的方块左下角横坐标离散后的编号
for (int i = 0; i < n; i++) {
x1[i] = id_x[x1[i]];
x2[i] = id_x[x2[i]];
yy1[i] = id_y[yy1[i]];
y2[i] = id_y[y2[i]];
events[x1[i]].push_back({i, ACTION_ADD});
events[x2[i]].push_back({i, ACTION_ERASE});
}
for (int i = 0; i < SZ; i++) {
mx[i] = -1;
}
int cnt_x = id_x.size();
for (int i = 0; i < cnt_x; i++) {
for (auto e : events[i]) {
int id = e.first;
int action = e.second;
if (action == ACTION_ERASE) {
erased[id] = true;
}
update(1, yy1[id], y2[id], id, action);
}
while (mx[1] != -1) {
int id = mx[1];
seen[id] = true;
//update在这里成了一个从所有叶子往上push的函数
update(1, yy1[id], y2[id], id, ACTION_VOID);
}
}
int ans = 1;
for (int i = 0; i < n; i++) {
if (seen[i]) {
ans++;
}
}
cout << ans;
}