• bzoj 1818: [Cqoi2010]内部白点


    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

    HINT

    Source

    题目看起来吓人且鬼畜,但是其实答案过了1s之后就不会变了;

    这个可以画一下图,如果某个方向缺了一个点,导致他不能变黑的话,那么这个方向上也不可能有点变黑了,从而他也不可能变黑,所以在1s之后答案确定;

    那么接下的问题就是一个扫描线的经典问题了,由于我们在计数的时候不能把原来的黑点也算进去,所以我们取横竖线段的时候要两两断开;

    扫描线的具体做法是,通过sort求出所有横线和竖线,然后把竖线拆为两条,从下往上扫描,

    遇到竖线的下端点就给该竖线的横坐标+1,遇到上端点就-1,然后遇到横线就查询一下横坐标范围内的权值和;

    通过树状数组实现单点修改和区间查询,注意在纵坐标相同时,优先级为撤销>查询>添加;

    //MADE BY QT666
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=500050;
    int n,hsh[N],tot,tmp;
    struct data{
        int x,y;
    }g[N];
    bool cmp1(const data &a,const data &b){
        if(a.x==b.x) return a.y<b.y;
        else return a.x<b.x;
    }
    bool cmp2(const data &a,const data &b){
        if(a.y==b.y) return a.x<b.x;
        else return a.y<b.y;
    }
    struct date{
        int l,r,x,y,op;
    }q[N];
    int find(int x){return lower_bound(hsh+1,hsh+1+tot,x)-hsh;}
    bool cmp3(const date &a,const date &b){
        if(a.y==b.y) return a.op<b.op;
        else return a.y<b.y;
    }
    int tr[N];
    int lowbit(int x){return x&-x;}
    void update(int x,int v){
        for(int i=x;i<=tot;i+=lowbit(i)) tr[i]+=v;
    }
    int query(int x){
        int ret=0;if(x==0) return 0;
        for(int i=x;i;i-=lowbit(i)) ret+=tr[i];
        return ret;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
    	scanf("%d%d",&g[i].x,&g[i].y);
    	hsh[++tot]=g[i].x;
        }
        sort(hsh+1,hsh+1+tot);tot=unique(hsh+1,hsh+1+tot)-hsh-1;
        sort(g+1,g+1+n,cmp1);
        for(int i=2;i<=n;i++){
    	if(g[i].x==g[i-1].x){
    	    tmp++;q[tmp].x=find(g[i-1].x),q[tmp].y=g[i-1].y,q[tmp].op=1;
    	    tmp++;q[tmp].x=find(g[i].x),q[tmp].y=g[i].y,q[tmp].op=-1;
    	}
        }
        sort(g+1,g+1+n,cmp2);
        for(int i=2;i<=n;i++){
    	if(g[i].y==g[i-1].y){
    	    tmp++;q[tmp].l=find(g[i-1].x),q[tmp].r=find(g[i].x),q[tmp].y=g[i].y,q[tmp].op=0;
    	}
        }
        sort(q+1,q+1+tmp,cmp3);int sum=0;
        for(int i=1;i<=tmp;i++){
    	if(q[i].op==1) update(q[i].x,1);
    	if(q[i].op==-1) update(q[i].x,-1);
    	if(q[i].op==0) sum+=query(q[i].r-1)-query(q[i].l);
        }
        printf("%d
    ",sum+n);
        return 0;
    }
    
  • 相关阅读:
    c# 扩展方法奇思妙用基础篇五:Dictionary<TKey, TValue> 扩展
    c# 扩展方法奇思妙用基础篇九:Expression 扩展
    c# 扩展方法奇思妙用高级篇一:改进 Scottgu 的 "In" 扩展
    c# 扩展方法奇思妙用高级篇三:Enumerable.Cast<T> 应用
    c# 扩展方法奇思妙用高级篇二:Aggregate 扩展及其改进
    c# 扩展方法奇思妙用基础篇四:Random 扩展
    c# 扩展方法奇思妙用基础篇七:IsBetween 通用扩展
    c# 扩展方法奇思妙用基础篇三:byte 常用扩展
    c# 扩展方法奇思妙用基础篇八:Distinct 扩展
    c# 扩展方法奇思妙用基础篇 六:WhereIf 扩展
  • 原文地址:https://www.cnblogs.com/qt666/p/7662234.html
Copyright © 2020-2023  润新知