题目描述
传送门
题目大意:无限大正方形网格里有n个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点)。每秒钟,所有内部白点同时变黑,直到不存在内部白点为止。你的任务是统计最后网格中的黑点个数。 内部白点的定义:一个白色的整点P(x,y)是内部白点当且仅当P在水平线的左边和右边各至少有一个黑点(即存在x1 < x < x2使得(x1,y)和(x2,y)都是黑点),且在竖直线的上边和下边各至少有一个黑点(即存在y1 < y < y2使得(x,y1)和(x,y2)都是黑点)。
题解
将坐标离散化,对于每一行维护存在黑点的最靠左/右的列,左端+1的位置权值+1,右端的位置权值-1
然后我们找出同列的相邻两个黑点的区间。
从左到右依次扫描每一列,将所有的在该列以及之前的操作都加入到线段树中,然后查询当前列区间的权值,计入答案即可。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define N 500003
#define LL long long
using namespace std;
struct data{
int opt,x,l,r,val;
}q[N];
struct node{
int x,y;
}a[N];
int n,x[N],y[N],dx[N],dy[N],L[N],R[N],st[N],cnt;
LL tr[N*4];
int cmp(node a,node b)
{
return a.y<b.y||a.y==b.y&&a.x<b.x;
}
int cmp1(data a,data b)
{
return a.x<b.x||a.x==b.x&&a.opt<b.opt;
}
void update(int now)
{
tr[now]=tr[now<<1]+tr[now<<1|1];
}
void pointchange(int now,int l,int r,int x,LL val)
{
if (l==r) {
tr[now]+=val;
return;
}
int mid=(l+r)/2;
if (x<=mid) pointchange(now<<1,l,mid,x,val);
else pointchange(now<<1|1,mid+1,r,x,val);
update(now);
}
LL query(int now,int l,int r,int ll,int rr)
{
if (ll>rr) return 0;
if (ll<=l&&r<=rr) return tr[now];
int mid=(l+r)/2;
LL ans=0;
if (ll<=mid) ans+=query(now<<1,l,mid,ll,rr);
if (rr>mid) ans+=query(now<<1|1,mid+1,r,ll,rr);
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) {
scanf("%d%d",&a[i].x,&a[i].y);
dx[++cnt]=a[i].x; dy[cnt]=a[i].y;
dx[++cnt]=a[i].x-1; dy[cnt]=a[i].y-1;
dx[++cnt]=a[i].x+1; dy[cnt]=a[i].y+1;
}
sort(dx+1,dx+cnt+1);
sort(dy+1,dy+cnt+1);
int cx=unique(dx+1,dx+cnt+1)-dx-1;
int cy=unique(dy+1,dy+cnt+1)-dy-1;
for (int i=1;i<=n;i++)
a[i].x=lower_bound(dx+1,dx+cx+1,a[i].x)-dx,
a[i].y=lower_bound(dy+1,dy+cy+1,a[i].y)-dy;
for (int i=1;i<=cx;i++) L[i]=cy+1;
for (int i=1;i<=n;i++) L[a[i].x]=min(L[a[i].x],a[i].y),R[a[i].x]=max(R[a[i].x],a[i].y);
sort(a+1,a+n+1,cmp); cnt=0;
for (int i=1;i<=cx;i++)
if (L[i]!=cy+1&&L[i]!=R[i]){
++cnt; q[cnt].opt=1; q[cnt].x=L[i]+1; q[cnt].l=i; q[cnt].val=1;
++cnt; q[cnt].opt=1; q[cnt].x=R[i]; q[cnt].l=i; q[cnt].val=-1;
}
int l=1;
for (int i=1;i<=cy;i++) {
int t1=0;
while (a[l].y==i&&l<=n) {
st[++t1]=a[l].x;
l++;
}
for (int j=2;j<=t1;j++) {
++cnt; q[cnt].opt=2; q[cnt].x=i; q[cnt].l=st[j-1]+1; q[cnt].r=st[j]-1;
}
}
sort(q+1,q+cnt+1,cmp1);
LL ans=n; l=1;
for (int i=1;i<=cy;i++) {
while (q[l].x<=i&&l<=cnt) {
if (q[l].opt==1) pointchange(1,1,cx,q[l].l,q[l].val);
else ans+=query(1,1,cx,q[l].l,q[l].r);
l++;
}
}
printf("%lld\n",ans);
}