Codeforces 983D Arkady and Rectangles 扫描线?

这篇文章写得挺好: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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值