bzoj 1818: [Cqoi2010]内部白点
Posted qt666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1818: [Cqoi2010]内部白点相关的知识,希望对你有一定的参考价值。
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
0 2
2 0
-2 0
0 -2
Sample Output
5
数据范围
36%的数据满足:n < = 500
64%的数据满足:n < = 30000
100%的数据满足:n < = 100000
数据范围
36%的数据满足:n < = 500
64%的数据满足:n < = 30000
100%的数据满足:n < = 100000
HINT
Source
题目看起来吓人且鬼畜,但是其实答案过了1s之后就不会变了;
这个可以画一下图,如果某个方向缺了一个点,导致他不能变黑的话,那么这个方向上也不可能有点变黑了,从而他也不可能变黑,所以在1s之后答案确定;
那么接下的问题就是一个扫描线的经典问题了,由于我们在计数的时候不能把原来的黑点也算进去,所以我们取横竖线段的时候要两两断开;
扫描线的具体做法是,通过sort求出所有横线和竖线,然后把竖线拆为两条,从下往上扫描,
遇到竖线的下端点就给该竖线的横坐标+1,遇到上端点就-1,然后遇到横线就查询一下横坐标范围内的权值和;
通过树状数组实现单点修改和区间查询,注意在纵坐标相同时,优先级为撤销>查询>添加;
//MADE BY QT666 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N=500050; int n,hsh[N],tot,tmp; struct data{ int x,y; }g[N]; bool cmp1(const data &a,const data &b){ if(a.x==b.x) return a.y<b.y; else return a.x<b.x; } bool cmp2(const data &a,const data &b){ if(a.y==b.y) return a.x<b.x; else return a.y<b.y; } struct date{ int l,r,x,y,op; }q[N]; int find(int x){return lower_bound(hsh+1,hsh+1+tot,x)-hsh;} bool cmp3(const date &a,const date &b){ if(a.y==b.y) return a.op<b.op; else return a.y<b.y; } int tr[N]; int lowbit(int x){return x&-x;} void update(int x,int v){ for(int i=x;i<=tot;i+=lowbit(i)) tr[i]+=v; } int query(int x){ int ret=0;if(x==0) return 0; for(int i=x;i;i-=lowbit(i)) ret+=tr[i]; return ret; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%d",&g[i].x,&g[i].y); hsh[++tot]=g[i].x; } sort(hsh+1,hsh+1+tot);tot=unique(hsh+1,hsh+1+tot)-hsh-1; sort(g+1,g+1+n,cmp1); for(int i=2;i<=n;i++){ if(g[i].x==g[i-1].x){ tmp++;q[tmp].x=find(g[i-1].x),q[tmp].y=g[i-1].y,q[tmp].op=1; tmp++;q[tmp].x=find(g[i].x),q[tmp].y=g[i].y,q[tmp].op=-1; } } sort(g+1,g+1+n,cmp2); for(int i=2;i<=n;i++){ if(g[i].y==g[i-1].y){ tmp++;q[tmp].l=find(g[i-1].x),q[tmp].r=find(g[i].x),q[tmp].y=g[i].y,q[tmp].op=0; } } sort(q+1,q+1+tmp,cmp3);int sum=0; for(int i=1;i<=tmp;i++){ if(q[i].op==1) update(q[i].x,1); if(q[i].op==-1) update(q[i].x,-1); if(q[i].op==0) sum+=query(q[i].r-1)-query(q[i].l); } printf("%d\n",sum+n); return 0; }
以上是关于bzoj 1818: [Cqoi2010]内部白点的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ1818[Cqoi2010]内部白点 扫描线+树状数组