1. 程式人生 > >BZOJ1818: [Cqoi2010]內部白點

BZOJ1818: [Cqoi2010]內部白點

所有 水平 b+ 答案 light 豎直 discuss status main

1818: [Cqoi2010]內部白點

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 1004 Solved: 485
[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

思路{

  想怎麽統計呢,發現在第一次一定算完了所有的點.那麽現在問題變成了算有多少個點滿足上下左右都有點.

  不妨轉化為線段求交.抽象成一些橫線,豎線.豎線交橫線產生貢獻.

  怎麽統計貢獻呢???

  好的,用從下往上的掃描線就可以了,

  碰到豎線下端點,x坐標位置+1,上端點的話-1.遇到橫線統計一段x之內的答案就可以了

  註意同一高度線段的掃描順序可以把豎線拆成兩個點.

}

  

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define N 1000001
#define lowbit ( (i) & (-i) )
#define LL long long
using namespace std;
struct point{
  int x,y;
  void read(){scanf("%d%d",&x,&y);}
}p[N];
struct seg{
  int h1,h2,h3,flag;
  seg() {}
  seg(int x,int y,int z,int a):h1(x),h2(y),h3(z),flag(a) {}
}s[N];
int tree[N],n,tot,sz,sub[N];
void Insert(int pos,int num){for(int i=pos;i<=n;i+=lowbit)tree[i]+=num;}
int Query(int pos){int sum(0);for(int i=pos;i;i-=lowbit)sum+=tree[i];return sum;}
int find(int x){
  return lower_bound(sub+1,sub+sz+1,x)-sub;
}
void link(int ff,int l,int r,int h){//0橫線,1豎線
  if(!ff){
    s[++tot]=seg(find(l),find(r),h,0);
  }else {
    int X=find(h);
    s[++tot]=seg(X,X,l,1);
    s[++tot]=seg(X,X,r,-1);
  }
}
bool comp(const point & a,const point & b){return a.x==b.x?a.y<b.y:a.x<b.x;}
bool Comp(const point & a,const point & b){return a.y==b.y?a.x<b.x:a.y<b.y;}
bool COMP(const seg & a,const seg & b){
  if(a.h3!=b.h3)return a.h3<b.h3;
  return a.flag<b.flag;
}
void build(){
  sort(p+1,p+n+1,comp);
  for(int i=2;i<=n;++i)
    if(p[i].x==p[i-1].x)
      link(1,p[i-1].y,p[i].y,p[i].x);
  sort(p+1,p+n+1,Comp);
  for(int i=2;i<=n;++i)
    if(p[i].y==p[i-1].y)
      link(0,p[i-1].x,p[i].x,p[i].y);
  sort(s+1,s+tot+1,COMP);
}
int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;++i)p[i].read(),sub[++sub[0]]=p[i].x;
  sort(sub+1,sub+sub[0]+1);
  sz=unique(sub+1,sub+sub[0]+1)-sub-1;
  build();LL Ans(0);
  for(int i=1;i<=tot;++i){
    if(!s[i].flag)Ans+=Query(s[i].h2-1)-Query(s[i].h1);
    else Insert(s[i].h1,s[i].flag);
  }cout<<Ans+n;
  return 0;
}

BZOJ1818: [Cqoi2010]內部白點