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

【BZOJ】1818: [Cqoi2010]内部白点(树状数组+离散+特殊的技巧)的更多相关文章

  1. BZOJ 1818: [Cqoi2010]内部白点(树状数组)

    传送门 解题思路 首先一定不可能有\(-1\)的情况,因为新产生的黑点不会造成任何贡献,它的各个方面都是不优的.那么只需要统计一遍答案,首先要将横坐标相同的两个点看成一条竖线,纵坐标相同的点看成一条横 ...

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

    这个题的想法很好想,就是进行排序之后直接检查每个点的上下左右是否有黑点就行.但是直接枚举显然不行,那怎么办呢?我们就用树状数组维护扫描线,把每排左右点看成一条线覆盖,然后从下往上扫,遇到下加一,遇到上 ...

  3. BZOJ 1818: [Cqoi2010]内部白点 扫描线+树状数组

    问题转化为求每一个极长横线段与极长纵线段的交点个数. 这个东西用扫描线+树状数组维护一下就可以了. code: #include <cstdio> #include <algorit ...

  4. bzoj 1818: [Cqoi2010]内部白点

    #include<cstdio> #include<iostream> #include<algorithm> using namespace std; struc ...

  5. bzoj 1818 Cqoi2010 内部白点 扫描线

    [Cqoi2010]内部白点 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1126  Solved: 530[Submit][Status][Disc ...

  6. BZOJ 1818: [Cqoi2010]内部白点 (BIT + 扫描线)

    就是求多条线段的交点数,直接BIT+扫描线就行了. 注意不要算重最初存在的点. CODE #include<bits/stdc++.h> using namespace std; char ...

  7. BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树

    [题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...

  8. [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

    题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...

  9. BZOJ 2743: [HEOI2012]采花 [树状数组 | 主席树]

    题意: 查询区间中出现次数$>2$的颜色个数 一眼主席树,区间中$l \le last[i] \le r$的个数减去$l \le last[last[i]] \le r$的个数,搞两颗主席树来做 ...

随机推荐

  1. 【云计算】K8S DaemonSet 每个node上都运行一个pod

    Kubernetes容器集群中的日志系统集成实践 Kubernetes是原生的容器编排管理系统,对于负载均衡.服务发现.高可用.滚动升级.自动伸缩等容器云平台的功能要求有原生支持.今天我分享一下我们在 ...

  2. Plus One Linked List

    Given a non-negative number represented as a singly linked list of digits, plus one to the number. T ...

  3. 利用VMware虚拟机(Android-x86 2.2)和eclipse,调试安卓代码

    下载 android-x86-2.2-generic.iso (这里包含eth0)  http://www.android-x86.org/download XP32位 只能使用 VMware Wor ...

  4. BestCoder18 1002.Math Problem(hdu 5105) 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5105 题目意思:给出一个6个实数:a, b, c, d, l, r.通过在[l, r]中取数 x,使得 ...

  5. HDU 4334 Trouble (暴力)

    Trouble Time Limit: 5000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Submit Statu ...

  6. javascript基础总结

    一.语法 ------------------------------ javascript中的一切(变量.函数名和操作符)都区分大小写. 标识符:就是指变量.函数.属性的名字,标识符要求如下 1 第 ...

  7. cf112a(水题)

    题目很简单..不过题意好像有点难懂... 题意:判定一个数能否被一个幸运数整除,循环一遍4到n/4,若存在i为幸运数且被n整除输出yes,反之输出no... 代码如下: #include <bi ...

  8. eclipse 向HDFS中创建文件夹报错 permission denied

    环境:win7  eclipse    hadoop 1.1.2 当执行创建文件的的时候, 即: String Path = "hdfs://host2:9000"; FileSy ...

  9. 【小技巧】9针USB转串口简易连通性测试,附25针转9针

    Part 1 前言 最近用SecureCRT连接串口,因为是笔记本用的USB转串口,好多次出现安装驱动OK,连接上了,但是没有串口打印.无法进行控制的问题:所以不清楚是USB串口的驱动问题,还是转接用 ...

  10. Java Hour 61 基础概念拾遗

    循环遍历器 for (Iterator iter = list.iterator(); iter.hasNext();) { int i = ((Integer) iter.next()).intVa ...