bzoj1818
来源:互联网 发布:软件系统业务流程图 编辑:程序博客网 时间:2024/05/16 01:17
1818: [Cqoi2010]内部白点
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 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
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
树状数组好题,值得一做,题意就是给若干条横线和竖线,问共有多少个点?其中点包括线段的端点和线段的交点。
怎么搞?首先我们需要对一个方向离散化,这里我对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
- bzoj1818
- 【bzoj1818】[Cqoi2010]内部白点
- 【bzoj1818】[Cqoi2010]内部白点
- [BZOJ1818] [Cqoi2010]内部白点
- bzoj1818[Cqoi2010]内部白点
- 【bzoj1818】[Cqoi2010]内部白点
- bzoj1818: [Cqoi2010]内部白点
- bzoj1818: [Cqoi2010]内部白点
- 【bzoj1818】 CQOI2010内部白点 树状数组计数
- BZOJ1818: [Cqoi2010]内部白点 树状数组+离散化
- [BZOJ1818][Cqoi2010]内部白点(扫描线+线段树)
- BZOJ1818 [Cqoi2010]内部白点 扫描线/线段求交
- 黑马程序员--封装--java
- linux设备模型之Kobject与Kset
- 黑马程序员—-C语言入门十重奏之九相守
- 学习java核心技术第3章的读书笔记
- OC_继承_类别_复合
- bzoj1818
- 自己动手写操作系统之参考资料
- 解决os x版xampp的mysql数据库无法开启的问题
- 3、Redis 集群特性之容错、数据迁移
- android开发——自定义相机(Camera)开发总结
- C的小算法集合
- 黑马程序员--java基础--面向对象概述
- 哈希运用于大数据查找中
- 文明就是收钱