BZOJ1818: [Cqoi2010]内部白点

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;
}
时间: 2024-08-12 06:59:09

BZOJ1818: [Cqoi2010]内部白点的相关文章

【BZOJ1818】[Cqoi2010]内部白点 扫描线+树状数组

[BZOJ1818][Cqoi2010]内部白点 Description 无限大正方形网格里有n个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点).每秒钟,所有内部白点同时变黑,直到不存在内部白点为止.你的任务是统计最后网格中的黑点个数. 内部白点的定义:一个白色的整点P(x,y)是内部白点当且仅当P在水平线的左边和右边各至少有一个黑点(即存在x1 < x < x2使得(x1,y)和(x2,y)都是黑点),且在竖直线的上边和下边各至少有一个黑点(即存在y1 <

1818: [Cqoi2010]内部白点

1818: [Cqoi2010]内部白点 15:08:51 Description 无限大正方形网格里有n个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点).每秒钟,所有内部白点同时变黑,直到不存在内部白点为止.你的任务是统计最后网格中的黑点个数. 内部白点的定义:一个白色的整点P(x,y)是内部白点当且仅当P在水平线的左边和右边各至少有一个黑点(即存在x1 < x < x2使得(x1,y)和(x2,y)都是黑点),且在竖直线的上边和下边各至少有一个黑点(即存在y1

B1818 [Cqoi2010]内部白点 树状数组

这个题的想法很好想,就是进行排序之后直接检查每个点的上下左右是否有黑点就行.但是直接枚举显然不行,那怎么办呢?我们就用树状数组维护扫描线,把每排左右点看成一条线覆盖,然后从下往上扫,遇到下加一,遇到上减一并记录答案.这样用扫描线维护就行了. 题干: Description 无限大正方形网格里有n个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点).每秒钟,所有内部白点同时变黑,直到不存在内部白点为止.你的任务是统计最后网格中的黑点个数. 内部白点的定义:一个白色的整点P(

BZOJ 1818: [Cqoi2010]内部白点

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1818 扫描线+树状数组. 首先可以看出题目其实是求有多少点上下左右至少有一个黑点. 拿x轴离散化,对x轴排一次序,于是我们可以拿出每一条竖线,把它拆成两个事件点,一个+1,一个-1,然后再对y轴排一次序,当作一条事件线段,记下左右端点. 然后对于这些事件按y轴排一次序,然后树状数组就可以了. #include<cstring> #include<iostream> #inclu

BZOJ 1818 内部白点(离散化+树状数组)

此题就是1227 的弱化版. 画个图或者稍微证明一下就能够知道,一定不会超过一次变换. 那么我们只需要统计有多少个白点会变黑,换句话说就是有多少个白点上下左右都有黑点. 离散化横坐标,因为没有黑点在的列是没有任何意义的,对答案也没有贡献. 然后处理每一行,对于每一行,维护一个BIT也就是哪些点会产生贡献,这个BIT最多只会有n次修改,n次查询. 所以时间复杂度为O(nlogn). # include <cstdio> # include <cstring> # include &l

BZOJ 1818 内部白点

扫描线. cmp不要乱打.....最后一个一定不要if直接return. 感谢http://hzwer.com/1836.html #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100500 using namespace std; int n,hash[maxn],top=0,t[maxn],cnt=0; struct pnt {

bzoj 1818 [CQOI 2010] 内部白点 - 扫描线 - 树状数组

题目传送门 快速的列车 慢速的列车 题目大意 一个无限大的方格图内有$n$个黑点.问有多少个位置上下左右至少有一个黑点或本来是黑点. 扫描线是显然的. 考虑一下横着的线段,取它两个端点,横坐标小的地方放一个+1,大的地方放一个-1事件. 然后扫描,扫到的横着的线段更新,竖着的线段用树状数组求答案. 然后考虑这一列上原来存在的黑点有没有被统计,如果没有就加上. Code 1 /** 2 * bzoj 3 * Problem#1818 4 * Accepted 5 * Time: 1824ms 6

待 题表

题表 达哥终极杂题表Bzoj2839 hdu6021 Codeforces 804DBzoj2248 hdu5575 Codeforces 786CBzoj2013 bzoj2676 Codeforces 803CBzoj2386 bzoj3782 Codeforces 813DBzoj2699 cogs1667 Codeforces 814DBzoj4798 bzoj2064 Codeforces 814EBzoj4639 bzoj3505 Codeforces 815ABzoj4417 bz

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734