zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    Linux 下的类似Windows下Everything的搜索工具
    windows和linux环境下制作U盘启动盘
    程序调试手段之gdb, vxworks shell
    LeetCode 1021. Remove Outermost Parentheses (删除最外层的括号)
    LeetCode 1047. Remove All Adjacent Duplicates In String (删除字符串中的所有相邻重复项)
    LeetCode 844. Backspace String Compare (比较含退格的字符串)
    LeetCode 860. Lemonade Change (柠檬水找零)
    LeetCode 1221. Split a String in Balanced Strings (分割平衡字符串)
    LeetCode 1046. Last Stone Weight (最后一块石头的重量 )
    LeetCode 746. Min Cost Climbing Stairs (使用最小花费爬楼梯)
  • 原文地址:https://www.cnblogs.com/zzmmm/p/7487423.html
Copyright © 2011-2022 走看看