题意
无限大正方形网格里有n个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点)。每秒钟,所有内部白点同时变黑,直到不存在内部白点为止。你的任务是统计最后网格中的黑点个数。 内部白点的定义:一个白色的整点P(x,y)是内部白点当且仅当P在水平线的左边和右边各至少有一个黑点(即存在x1 < x < x2使得(x1,y)和(x2,y)都是黑点),且在竖直线的上边和下边各至少有一个黑点(即存在y1 < y < y2使得(x,y1)和(x,y2)都是黑点)。
解题思路
可以把平行于坐标轴的黑点互相连接起来,就能把问题转换为求交点的个数+原先黑点的个数
然后想到利用扫描线(平行于y轴)的性质,在平行于x轴的线段,当扫描线至左端点加1,右端点减1
在平行于y轴的线段时,则查询[y1, y2]区间的区间和
因为区间和,可以联想到树状数组,或线段树,而这道题只是涉及单点更新,以及区间查询,所以用树状数组(下标是y)再好不过了
注:1.先将其进行离散化
2.对于线段赋值时,要注意,是横线时,它的左端点和右端点都要赋值,只不过它们的y1和y2相同
AC代码:
#include <bits/stdc++.h>
#define lowbit(x) x & (-x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
int n;
struct point {
int x, y;
} p[maxn];
bool cmpx(point a, point b) {
if (a.x != b.x) return a.x < b.x;
else return a.y < b.y;
}
bool cmpy(point a, point b) {
if (a.y != b.y) return a.y < b.y;
else return a.x < b.x;
}
int x[maxn], y[maxn];
struct L {
int x, y1, y2, shape, state; //shape为0为横线,shape为1为竖线
} line[maxn << 1];
bool cmpl(L A, L B) {
return A.x == B.x ? A.y1 < B.y1 : A.x < B.x;
}
int cnt = 0;
void init() {
sort (p + 1, p + n + 1, cmpx);//x从小到大排序,当x相同时,y从小到大排序
for (int i = 1; i <= n; i++)
if (p[i].x == p[i - 1].x) //说明是竖线
line[++cnt] = (L) {p[i].x, p[i - 1].y, p[i].y, 1, 0};//此时为竖线,所以state无需赋值
sort (p + 1, p + n + 1, cmpy);//y从小到大排序,当y相同时,x从小到大排序
for (int i = 1; i <= n; i++)
if (p[i].y == p[i - 1].y) //说明是横线
line[++cnt] = (L) {p[i - 1].x, p[i].y, p[i].y, 0, 1}, //左端点加1,左端点state为1
line[++cnt] = (L) {p[i].x, p[i].y, p[i].y, 0, -1}; //右端点减1,右端点state为-1
}
int c[maxn];
int query(int x) {
int res = 0;
while (x) res += c[x], x -= lowbit(x);
return res;
}
void update(int x, int y) {
while (x <= maxn) c[x] += y, x += lowbit(x);
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> p[i].x >> p[i].y;
x[i] = p[i].x, y[i] = p[i].y;
}
sort (x + 1, x + n + 1);
sort (y + 1, y + n + 1);
int cntx = unique(x + 1, x + n + 1) - x;
int cnty = unique(y + 1, y + n + 1) - y;
for (int i = 1; i <= n; i++)//对x和y进行离散化
p[i].x = lower_bound(x + 1, x + cntx + 1, p[i].x) - x,
p[i].y = lower_bound(y + 1, y + cnty + 1, p[i].y) - y;
init();//这里对线段进行赋值
sort (line + 1, line + cnt + 1, cmpl);
ll ans = n;
for (int i = 1; i <= cnt; i++)
if (line[i].shape == 0) update(line[i].y1, line[i].state);
else ans += query(line[i].y2 - 1) - query(line[i].y1);
//这样处理是因为,可能会有本身就有符合条件的黑点
cout << ans << endl;
}