bzoj1818

来源:互联网 发布:软件系统业务流程图 编辑:程序博客网 时间:2024/05/16 01:17

1818: [Cqoi2010]内部白点

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 571  Solved: 281
[Submit][Status][Discuss]

Description

无限大正方形网格里有n个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点)。每秒钟,所有内部白点同时变黑,直到不存在内部白点为止。你的任务是统计最后网格中的黑点个数。 内部白点的定义:一个白色的整点P(x,y)是内部白点当且仅当P在水平线的左边和右边各至少有一个黑点(即存在x1 < x < x2使得(x1,y)和(x2,y)都是黑点),且在竖直线的上边和下边各至少有一个黑点(即存在y1 < y < y2使得(x,y1)和(x,y2)都是黑点)。

Input

输入第一行包含一个整数n,即初始黑点个数。以下n行每行包含两个整数(x,y),即一个黑点的坐标。没有两个黑点的坐标相同,坐标的绝对值均不超过109。

Output

输出仅一行,包含黑点的最终数目。如果变色过程永不终止,输出-1。

Sample Input

4

0 2

2 0

-2 0

0 -2

Sample Output

5



数据范围

36%的数据满足:n < = 500

64%的数据满足:n < = 30000

100%的数据满足:n < = 100000


树状数组好题,值得一做,题意就是给若干条横线和竖线,问共有多少个点?其中点包括线段的端点和线段的交点。

怎么搞?首先我们需要对一个方向离散化,这里我对y坐标离散化了,那么我们要从上往下扫描,当扫描的竖线的上端后,我们在该竖线的纵坐标(离散化后的)上+1,表示这个位置上有一条竖线正在往下延伸,可想而知如果继续从上往下扫,下一条是横线,并且横线的左右端点[L,R]包含刚才竖线的纵坐标,那么显然横线与纵线相交了,因为此时纵线的下端点还没扫出来,必然知道纵线的下端点在横线下方(先不考虑刚好在横线上),这样上端点与下端点位于横线两端,所以相交是必然的。

这给了我们一个启示,我们从上往下扫描,如果扫到竖线的上端点,就在对应纵坐标+1,下端点则-1,横线则统计[L,R]区间的和,再回到刚才问题,竖线刚好在横线上,那么你必须给一个顺序,首先是竖线下端点,其次是横线,再其次是竖线上端点,为什么呢?如果竖线下端点在横线之后,那么我们就会先扫描横线,此时该条竖线的上端点就有可能对横线贡献一次,其实这一次显然是下端点刚好在横线,虽然是有一个交点,但这个交点本来就是线段的端点,并不是新产生的,因此没必要计算,所以先下端点在横线的话,那么在下端点插入时会-1,这样就不会统计进去了。同理可以判断横线在竖线上端点前面。

然后就是代码:

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#define Maxn 100010using namespace std;struct edge{    int x,l,r,d;    edge(int _x=0,int _l=0,int _r=0,int _d=0):x(_x),l(_l),r(_r),d(_d){}    bool operator<(const edge &a)const{        return x<a.x||x==a.x&&d>a.d; //x相同,纵线下端>横线>纵线上端    }}e[Maxn*2];struct point{    int x,y;    bool operator<(const point &a)const{        return x<a.x||x==a.x&&y<a.y;    }    void read(){        scanf("%d%d",&x,&y);    }}p[Maxn];bool cmp(point a,point b){    return a.y<b.y||a.y==b.y&&a.x<b.x;}int Y[Maxn];int n,m;int cal(int y){ //返回离散化后数组的元素下标+1    return lower_bound(Y,Y+m,y)-Y+1;}int c[Maxn];void add(int x,int y){    while(x<=n){        c[x]+=y;        x+=x&-x;    }}int sum(int x){    int ans=0;    while(x){        ans+=c[x];        x-=x&-x;    }    return ans;}int main(){    scanf("%d",&n);    for(int i=0;i<n;i++){        p[i].read();        Y[i]=p[i].y;    }    sort(Y,Y+n);    m=unique(Y,Y+n)-Y; //对Y离线化    sort(p,p+n); //先x后y    int tot=0;    for(int i=1;i<n;i++){        if(p[i].x==p[i-1].x)            e[tot++]=edge(p[i].x,cal(p[i-1].y),cal(p[i].y),0); //横线(询问)    }    sort(p,p+n,cmp); //先y后x    for(int i=1;i<n;i++){        if(p[i].y==p[i-1].y){            e[tot++]=edge(p[i-1].x,cal(p[i-1].y),0,-1); //纵线上端            e[tot++]=edge(p[i].x,cal(p[i].y),0,1); //纵线下端        }    }    sort(e,e+tot);    int ans=n;    for(int i=0;i<tot;i++){ //从上往下扫描        if(!e[i].d) //横线询问            ans+=sum(e[i].r)-sum(e[i].l-1);        else //纵线插入            add(e[i].l,-e[i].d);    }    printf("%d\n",ans);return 0;}


0 0
原创粉丝点击