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

Sample Output

5

数据范围
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;
}
1818(wypx)(wa)

by:wypx


其实暴力什么的最神奇了的说♪

 

思路:先以一个坐标轴找到每一个的最左&右的点,然后再这个图中加竖着的线,把线上的点记录一个bool数组,每一次扫横线上的被标记的个数,用n+这样找出的点就好了的说。O(∩_∩)O哈哈哈~(1e5的平方还是能接受的范围)
by:s_a_b_e_r

s:不想做题了,炉石什么的出橙卡的说,体现新卡的乐趣中.......
w:到底哪不对啊QAQ(少女崩溃中)
原文地址:https://www.cnblogs.com/ck666/p/7428159.html