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\n", ans);
}
int main() {return work(), 0;}