P5816 [CQOI2010]内部白点

题目描述

无限大正方形网格里有(n)个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点)。每秒钟,所有内部白点同时变黑,直到不存在内部白点为止。你的任务是统计最后网格中的黑点个数。

内部白点的定义:一个白色的整点(P(x,y))是内部白点当且仅当(P)在水平线的左边和右边各至少有一个黑点(即存在(x_1 < x < x_2)使得((x_1,y))((x_2,y))都是黑点),且在竖直线的上边和下边各至少有一个黑点(即存在(y_1 < y < y_2)使得((x,y_1))((x,y_2))都是黑点)。

题解

我们首先对所有的点按照以纵坐标为第一关键字从大到小,以横坐标为第二关键字从小到大排序,然后对横坐标进行离散化。

我们预处理出来对于每一个横坐标它的纵坐标的上界和下界。

然后按顺序扫所有的点,用线段树维护一个横坐标是否可行,如果该点的纵坐标是某个横坐标的上界就在这个横坐标处加一,如果是下界就减一。

当换行时我们统计一下该行的贡献即可。

详见代码。

#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f;
int n, tr[N << 2], b[N], len, up[N], down[N], L;
ll ans;
struct node{int x, y;}d[N];
inline int read()
{
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
bool cmp(const node & a, const node & b) {return a.y == b.y ? a.x < b.x : a.y > b.y;}
void change(int k, int l, int r, int x, int val)
{
	if(l == r) return tr[k] += val, void();
	int mid = (l + r) >> 1;
	if(x <= mid) change(k << 1, l, mid, x, val);
	else change(k << 1 | 1, mid + 1, r, x, val);
	tr[k] = tr[k << 1] + tr[k << 1 | 1];
}
int query(int k, int l, int r, int x, int y)
{
	if(x <= l && r <= y) return tr[k];
	int mid = (l + r) >> 1, ans = 0;
	if(x <= mid) ans += query(k << 1, l, mid, x, y);
	if(y > mid) ans += query(k << 1 | 1, mid + 1, r, x, y);
	return ans;
}
void work()
{
	n = read();
	for(int i = 1; i <= n; i ++)
	{
		b[i] = d[i].x = read(); d[i].y = read();
		up[i] = -inf; down[i] = inf;
	}
	sort(d + 1, d + n + 1, cmp);
	sort(b + 1, b + n + 1); len = unique(b + 1, b + n + 1) - b - 1;
	for(int i = 1; i <= n; i ++)
	{
		d[i].x = lower_bound(b + 1, b + len + 1, d[i].x) - b;
		up[d[i].x] = max(up[d[i].x], d[i].y);
		down[d[i].x] = min(down[d[i].x], d[i].y);
	}
	L = d[1].x; d[n + 1].y = inf;//·ÀÖ¹d[n].y = 0; 
	for(int i = 1; i <= n; i ++)
	{
		if(d[i].y == up[d[i].x]) change(1, 1, len, d[i].x, 1);
		if(d[i].y == down[d[i].x]) ans ++, change(1, 1, len, d[i].x, -1);//²»ÄÜelse
		if(d[i].y != d[i + 1].y)
		{
			ans += query(1, 1, len, L, d[i].x);
			L = d[i + 1].x;
		}
	}
	printf("%lld
", ans);
}
int main() {return work(), 0;}
原文地址:https://www.cnblogs.com/Sunny-r/p/12692675.html