zoukankan      html  css  js  c++  java
  • 【BZOJ】1818: [Cqoi2010]内部白点(树状数组+离散+特殊的技巧)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1818

    这一题一开始我就看错了,bzoj的那个绝对值109简直坑人,应该是10^9,我直接写了个暴力。。简直感人。

    然后看题解,看了挺久,,,,后来明白了。。

    首先我们离散x轴,这样将数量级降到n。

    然后我们知道,黑点在一秒内就会全部出来了,不可能有黑点在一秒后再由新的黑点组成,这点显而易见。

    所以不必考虑-1的情况,因为不可能

    产生黑点是什么情况呢?当然是水平黑点线段和竖直黑点线段的交点!

    所以我们要处理出所有的线段

    怎样判交呢?

    扫描线

    将所有的线段按y轴排序,一直扫上去

    怎么统计呢?

    用树状数组维护1~n(离散后的x轴)在此时扫描线所在位置的总和。

    我们先来考虑横线的情况,横线当然是直接在扫描线统计,但是要注意,不能包括左右两个端点,即树状数组统计sum(r-1)-sum(l)

    我们在向上扫到竖线的时候,如果是下端点,那么就将这个x轴+1,如果扫描到了它的上端点,那么x轴就-1

    具体看代码,很多细节

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << #x << " = " << x << endl
    #define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; }
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    inline const int max(const int &a, const int &b) { return a>b?a:b; }
    inline const int min(const int &a, const int &b) { return a<b?a:b; }
    
    const int N=100005;
    int hash[N], n, line, cnt, ans, c[N];
    struct ND { int x, y; }nd[N];
    struct seg { int x, y, r, k; }s[N*10]; //这里的k别有用心,按k排序的话,刚好可以将完结的竖条先剪掉,然后再将横条的统计,然后再加上y轴的竖条。。太赞了
    inline const bool cmp1(const ND &a, const ND &b) { return a.x==b.x ? a.y<b.y : a.x<b.x; } //竖
    inline const bool cmp2(const ND &a, const ND &b) { return a.y==b.y ? a.x<b.x : a.y<b.y; } //横
    inline const bool cmp3(const seg &a, const seg &b) { if(a.y==b.y) return a.k<b.k; return a.y<b.y; }
    inline const int ifind(const int &x) { return lower_bound(hash+1, hash+1+line, x)-hash; }
    inline void add(const int &x, const int &r, const int &y, const bool &d) {
    	if(d) { //竖 r下边的,y上边的
    		int fx=ifind(x);
    		s[++cnt].x=fx; s[cnt].y=r; s[cnt].k=1;
    		s[++cnt].x=fx; s[cnt].y=y; s[cnt].k=-1;
    	}
    	else { s[++cnt].x=ifind(x); s[cnt].r=ifind(r); s[cnt].y=y; }
    }
    void build() {
    	sort(nd+1, nd+1+n, cmp1);
    	for2(i, 1, n) if(nd[i].x==nd[i+1].x) add(nd[i].x, nd[i].y, nd[i+1].y, 1);
    	sort(nd+1, nd+1+n, cmp2);
    	for2(i, 1, n) if(nd[i].y==nd[i+1].y) add(nd[i].x, nd[i+1].x, nd[i].y, 0);
    }
    inline int sum(int x) { int ret=0; for(; x; x-=(x&-x)) ret+=c[x]; return ret; }
    inline void update(int x, const int &y) { for(; x<=line; x+=(x&-x)) c[x]+=y; }
    void getans() {
    	for1(i, 1, cnt)
    		if(!s[i].k) ans+=sum(s[i].r-1)-sum(s[i].x);
    		else update(s[i].x, s[i].k);
    }
    int main() {
    	read(n);
    	for1(i, 1, n) { read(nd[i].x); read(nd[i].y); hash[i]=nd[i].x; }
    	sort(hash+1, hash+1+n); hash[n+1]=~0u>>1;
    	for1(i, 1, n) if(hash[i]!=hash[i+1]) hash[++line]=hash[i];
    	build();
    	sort(s+1, s+1+cnt, cmp3);
    	getans();
    	print(n+ans);
    	return 0;
    }
    

    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

  • 相关阅读:
    TCP 连接状态
    可视化垃圾回收算法
    flume-ng+Kafka+Storm+HDFS 实时系统搭建
    WeX5 IDE 手机移动开发+JAVA +大数据
    云计算高级运维工程师
    CentOS 5.8 上安装 systemtap-2.6
    SYSTEMTAP -ORACLE
    Apple激活日期查询
    Div 浮动到另一个div之上
    Python模块常用的几种安装方式
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/3945768.html
Copyright © 2011-2022 走看看