bzoj 1818: [Cqoi2010]内部白点 (扫描线+线段树)

来源:互联网 发布:php 极客学院 编辑:程序博客网 时间:2024/04/28 14:42

题目描述

传送门

题目大意:无限大正方形网格里有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);}
0 0
原创粉丝点击