bzoj 1818 [CQOI2010]内部白点
1818: [CQOI2010]内部白点
2017-08-25
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
这个题hzwer学长说想了一个小时
于是我们开始想
……
于是第二天我们开始找题解……
…………
于是第三天我们弃坑了x
意外的很难搞……
读入数据之后先离散一下,把10^9压到10^5
接着把点分别按xy坐标排序,每两点建一条线
这里有个玄学的技巧
把竖着的线不当做线处理
而是把两个端点看做两条长度为0的横线
并分别给上下端点附上一个+1、-1的值k
最后把边按y为第一关键字,k为第二关键字排序,遍历所有线
维护一个树状数组
对于竖线(端点),将树状数组对应的x位置+1或-1
对于横线l~r,把答案加上树状数组中l~r-1的和(因为两端端点不加)
这样全部扫一遍就可以了
……所以为什么不对啊
调了好久还是没过……
并不知道错哪了
求dalao指点啊qwq
附上错误代码
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=100009; struct node{int x,y;}a[N]; struct segm{int l,r,y,k;}s[N]; bool cmpx(node x,node y){if(x.x==y.x)return x.y<y.y;return x.x<y.x;} bool cmpy(node x,node y){if(x.y==y.y)return x.x<y.x;return x.y<y.y;} bool cmps(segm x,segm y){if(x.y==y.y)return x.k<y.k;return x.y<y.y;} int lowbit(int k){return k&(-k);} int n,cnt,ans,sum[N]; void update(int k,int x) { while(k<=n) { sum[k]+=x; k+=lowbit(k); } } int found(int k) { int s=0; while(k) { s+=sum[k]; k-=lowbit(k); } return s; } int main() { scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d%d",&a[i].x,&a[i].y); // cout<<"discretization"<<endl; sort(a+1,a+n+1,cmpx); int l,r,tot=1,maxx=1,maxy=1; while(tot<=n){ l=r=tot; while(a[l].x==a[r].x)r++; while(l<r)a[l].x=maxx,l++; maxx++,tot=r; } sort(a+1,a+n+1,cmpy); tot=1; while(tot<=n){ l=r=tot; while(a[l].y==a[r].y)r++; while(l<r)a[l].y=maxy,l++; maxy++,tot=r; } // cout<<"addline"<<endl; for(int i=2;i<=n;++i) if(a[i].y==a[i-1].y) { ++cnt; s[cnt].l=a[i-1].x; s[cnt].r=a[i].x; s[cnt].y=a[i].y; } sort(a+1,a+n+1,cmpx); for(int i=2;i<=n;++i) if(a[i].x==a[i-1].x) { ++cnt; s[cnt].l=s[cnt].r=a[i].x; s[cnt].y=a[i-1].y; s[cnt].k=1; ++cnt; s[cnt].l=s[cnt].r=a[i].x; s[cnt].y=a[i].y; s[cnt].k=-1; } // cout<<"scan"<<endl; sort(s+1,s+cnt+1,cmps); for(int i=1;i<=cnt;++i) { int k=s[i].k; if(k==0)ans+=found(s[i].r-1)-found(s[i].l); else update(s[i].l,k); } cout<<ans+n<<endl; system("pause"); return 0; }
by:wypx
其实暴力什么的最神奇了的说♪
思路:先以一个坐标轴找到每一个的最左&右的点,然后再这个图中加竖着的线,把线上的点记录一个bool数组,每一次扫横线上的被标记的个数,用n+这样找出的点就好了的说。O(∩_∩)O哈哈哈~(1e5的平方还是能接受的范围)
by:s_a_b_e_r
s:不想做题了,炉石什么的出橙卡的说,体现新卡的乐趣中.......
w:到底哪不对啊QAQ(少女崩溃中)