题目传送门

  题意:给出很多黑点,当一个坐标上下左右都有黑点时,这个点也被染成黑色,问最后黑点的数量。

  思路:首先,一个很显然的结论,不可能出现无限染色的情况。所以不会输出-1,当n为0或者1时,答案就是0或者1.

    其次,每一个新增的点其实就是横线和竖线的交点,我们先把所有的坐标都离散化,然后把横线和竖线都处理出来,分三类,横线,竖线的下端点,竖线的上端点,按照y从小到大排序。遇到竖线下端点时,树状数组x的位子加一,遇到上端点,x的位置减一,遇到横线,则是一段区间求和。

    比较重要的端点问题和处理这三类点(线)的优先级问题,显然应该先删去,再求和,最后加上,所以在结构体中加入一个flag,既表示种类又表示优先级。区间求和的时候端点要注意。

    我一开始将一条线上的所有点全部合并在同一条直线上,比如(1,1),(1,2),(1,3)直接合并成(1,1)到(1,3),这样处理首先很麻烦,其次会遇到某两条直线把(1,2)这个点染成黑色,重复计算的问题,所以只需要老老实实的分成很多线段就可以了。

#include<bits/stdc++.h>
#define CLR(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=;
struct node{
ll x,y;
}a[maxn];
struct line{
ll x1,y1,x2,y2;
int flag;//1下端点 2横线 3代表上端点
}b[maxn<<];
bool cmpx(const node &u,const node &v)
{
if(u.x==v.x)return u.y<v.y;
return u.x<v.x;
}
bool cmpy(const node &u,const node &v)
{
if(u.y==v.y)return u.x<v.x;
return u.y<v.y;
}
bool cmpli(const line &u,const line &v){
if(u.y1==v.y1)return u.flag>v.flag;
return u.y1<v.y1;
}
ll hash1[maxn<<],hash2[maxn<<];
int n,h;
inline void Hash(){
sort(hash1+,hash1++h);
int m=;
for(int i=;i<=h;i++)
{
if(i==||hash1[i]!=hash1[i-]){
hash2[++m]=hash1[i];
}
}
for(int i=;i<=n;i++)
{
a[i].x=lower_bound(hash2+,hash2++m,a[i].x)-hash2;
a[i].y=lower_bound(hash2+,hash2++m,a[i].y)-hash2;
}
} ll c[maxn<<];
inline void add(int x,ll val)
{
while(x<=)
{
c[x]+=val;
x+=(x&(-x));
}
}
inline ll getsum(int x)
{
ll res=;
while(x>)
{
res+=c[x];
x-=(x&(-x));
}
return res;
}
int main(){
cin>>n;
for(int i=;i<=n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].y);
hash1[++h]=a[i].x,hash1[++h]=a[i].y;
}
if(n<=){
printf("%d\n",n);
return ;
}
Hash();
sort(a+,a++n,cmpx);
ll xx=a[].x,yy=a[].y;
int totline=;
for(int i=;i<=n;i++)//竖线
{
if(a[i].x==xx)
{
b[totline].x1=xx;
b[totline].y1=yy;
b[totline].x2=a[i].x;
b[totline].y2=a[i].y;
xx=a[i].x;
yy=a[i].y;
totline++;
}else{
xx=a[i].x;
yy=a[i].y; }
if(i==n){
totline--;
}
}
sort(a+,a++n,cmpy);
for(int i=;i<=totline;i++)
{
b[i].flag=;
b[i+totline]=b[i];
b[i+totline].flag=;
b[i].x2=b[i].x1,b[i].y2=b[i].y1;
b[i+totline].x1=b[i+totline ].x2,b[i+totline].y1=b[i+totline ].y2;
}
totline<<=;
totline++;
xx=a[].x,yy=a[].y;
for(int i=;i<=n;i++)//竖线
{
if(a[i].y==yy)
{
b[totline].x1=xx;
b[totline].y1=yy;
b[totline].x2=a[i].x;
b[totline].y2=a[i].y;
b[totline].flag=;
xx=a[i].x;
yy=a[i].y;
totline++;
}else{
xx=a[i].x;
yy=a[i].y;
}
if(i==n)totline--;
}
sort(b+,b++totline,cmpli);
//1下端点 2横线 3代表上端点
// for(int i=1;i<=totline;i++)
// {
// printf("i:%d flag:%d x1:%d y1:%d x2:%d y2:%d\n",i,b[i].flag,b[i].x1,b[i].y1,b[i].x2,b[i].y2);
// }
ll ans=; for(int i=;i<=totline;i++)
{ if(b[i].flag==){
add(b[i].x1,);
}else if(b[i].flag==){
xx=b[i].x1,yy=b[i].x2;
if(yy->=xx+){
ans-=getsum(xx);
ans+=getsum(yy-);
} }else if(b[i].flag==){
add(b[i].x1,-);
}
}
printf("%lld\n",ans+n);
} /* 10
6 7
3 8
5 2
6 4
1 5
5 4
1 10
8 7
1 8
4 10 9
2 4
4 1
8 4
7 1
7 10
1 10
6 4
6 8
6 1 */

1818: [Cqoi2010]内部白点

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1418  Solved: 635
[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

bzoj1818 内部白点(好题) 离散化+树状数组的更多相关文章

  1. HDU 6318.Swaps and Inversions-求逆序对-线段树 or 归并排序 or 离散化+树状数组 (2018 Multi-University Training Contest 2 1010)

    6318.Swaps and Inversions 这个题就是找逆序对,然后逆序对数*min(x,y)就可以了. 官方题解:注意到逆序对=交换相邻需要交换的次数,那么输出 逆序对个数 即可. 求逆序对 ...

  2. CodeForces 540E - Infinite Inversions(离散化+树状数组)

    花了近5个小时,改的乱七八糟,终于A了. 一个无限数列,1,2,3,4,...,n....,给n个数对<i,j>把数列的i,j两个元素做交换.求交换后数列的逆序对数. 很容易想到离散化+树 ...

  3. Ultra-QuickSort(归并排序+离散化树状数组)

    Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 50517   Accepted: 18534 ...

  4. HDU 5862 Counting Intersections(离散化+树状数组)

    HDU 5862 Counting Intersections(离散化+树状数组) 题目链接http://acm.split.hdu.edu.cn/showproblem.php?pid=5862 D ...

  5. BZOJ_4627_[BeiJing2016]回转寿司_离散化+树状数组

    BZOJ_4627_[BeiJing2016]回转寿司_离散化+树状数组 Description 酷爱日料的小Z经常光顾学校东门外的回转寿司店.在这里,一盘盘寿司通过传送带依次呈现在小Z眼前.不同的寿 ...

  6. poj-----Ultra-QuickSort(离散化+树状数组)

    Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 38258   Accepted: 13784 ...

  7. Code Forces 652D Nested Segments(离散化+树状数组)

     Nested Segments time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...

  8. hdu 3015 Disharmony Trees (离散化+树状数组)

    Disharmony Trees Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  9. 【bzoj4627】[BeiJing2016]回转寿司 离散化+树状数组

    题目描述 给出一个长度为n的序列,求所有元素的和在[L,R]范围内的连续子序列的个数. 输入 第一行包含三个整数N,L和R,分别表示寿司盘数,满意度的下限和上限. 第二行包含N个整数Ai,表示小Z对寿 ...

  10. 【bzoj5055】膜法师 离散化+树状数组

    题目描述 给定一个序列$a$,求满足$i<j<k$且$a_i<a_j<a_k$的三元组$(i,j,k)$的个数. 输入 第一行1个数 n 第二行n个数 a_i 输出 一个数,表 ...

随机推荐

  1. Mask_RCNN训练模型初步测试结果

    调用训练的模型,加载测试集,发现测试效果并不理想,所以,需要调整训练参数,继续训练模型

  2. 关于pycharm字体大小的调整

    我们平常编写pyhton 可以用sublime eclipse 但是eclipse在后期需要安装很多插件,这很是麻烦,为了避免这种麻烦,我们采用pycharm来编写,但是刚装上的该软件 不建议同学们进 ...

  3. keydown、input 和 keyup 事件

    keydown.keyup 属于键盘事件,input 属于文本事件. keydown:当用户按下键盘上的任意按键时触发,如果按住不放,会重复触发此事件. keyup:当用户释放键盘上的按键时触发. i ...

  4. Controller级别的异常处理过滤器IExceptionFilter

    1,系统自带的HandleErrorAttribute类继承自IExceptionFilter,是MVC的默认实现. 同时设置web.config <system.web> <cus ...

  5. On the nightmare that is JSON Dates. Plus, JSON.NET and ASP.NET Web API

    Ints are easy. Strings are mostly easy. Dates? A nightmare. They always will be. There's different c ...

  6. Java 之集合框架

  7. Java Random、ThreadLocalRandom、UUID类中的方法应用(随机数)

    1.Random:产生一个伪随机数(通过相同的种子,产生的随机数是相同的): Random r=new Random(); System.out.println(r.nextBoolean()); S ...

  8. The Suspects——Asia Kaohsiung 2003

    原创 The Suspects Time Limit: 1000MS Memory Limit: 20000K Total Submissions: 48698 Accepted: 23286 Des ...

  9. Vue watch用法

    Vue.js 提供了一个方法 watch,它用于观察Vue实例上的数据变动.对应一个对象,键是观察表达式,值是对应回调.值也可以是方法名,或者是对象,包含选项. 例如,同一个组件切换时,不会触发生命周 ...

  10. c++缓冲区------c++ Primer Plus

    通常,通过使用缓冲区可以更高效地处理输入和输出.缓冲区是用作中介的内存块,它是将信息从设备传输到程序或从程序传输给设备的临时存储工具.通常,像硬盘驱动器这样的设备以512字节(或更多)的块为单位来传输 ...