ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Luogu5816 [CQOI2010]内部白点

2021-02-04 19:01:18  阅读:218  来源: 互联网

标签:ri le pt 黑点 白点 Luogu5816 int CQOI2010


原题链接:https://www.luogu.com.cn/problem/P5816

内部白点

题目描述

无限大正方形网格里有 n n n 个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点)。每秒钟,所有内部白点同时变黑,直到不存在内部白点为止。你的任务是统计最后网格中的黑点个数。

内部白点的定义:一个白色的整点 P ( x , y ) P(x,y) P(x,y) 是内部白点当且仅当 P P P 在水平线的左边和右边各至少有一个黑点(即存在 x 1 < x < x 2 x_1 < x < x_2 x1​<x<x2​ 使得 ( x 1 , y ) (x_1,y) (x1​,y) 和 ( x 2 , y ) (x_2,y) (x2​,y) 都是黑点),且在竖直线的上边和下边各至少有一个黑点(即存在 y 1 < y < y 2 y_1 < y < y_2 y1​<y<y2​ 使得 ( x , y 1 ) (x,y_1) (x,y1​) 和 ( x , y 2 ) (x,y_2) (x,y2​) 都是黑点)。

输入格式

输入第一行包含一个整数 n n n,即初始黑点个数。

以下 n n n 行每行包含两个整数 x x x, y y y,即一个黑点的坐标。没有两个黑点的坐标相同,坐标的绝对值均不超过 1 0 9 10^9 109。

输出格式

输出仅一行,包含黑点的最终数目。

如果变色过程永不终止,输出-1。

输入输出样例

输入 #1
4
0 2
2 0
-2 0
0 -2
输出 #1
5

说明/提示

数据范围

对于 36 % 36\% 36% 的数据, n ≤ 500 n \le 500 n≤500。

对于 64 % 64\% 64% 的数据, n ≤ 3 × 1 0 4 n \le 3 \times 10^4 n≤3×104 。

对于 100 % 100\% 100% 的数据, n ≤ 1 0 5 n \le 10^5 n≤105 。

题解

思路比较简单,但是细节挺多。

首先,必定不会有 − 1 -1 −1的情况出现,因为一个点从白点变成黑点当且仅当这个白点上下左右都有黑点,而这个白点变成黑点后,它的作用完全可以被催生它的四个黑点取代,即如果新的黑点可以让其他白点变黑那么原来的黑点一样可以。

解决了这个问题,我们就不需要再纠结新产生的黑点对其他白点的影响了,利用初始条件给定的黑点我们就能一次得出答案。

下面考虑怎么一次求出答案,白点变黑点的条件是上下左右均有黑点,我们同样可以套用扫描线的思路,数据结构维护一维,延伸推进一维。在这道题中,可以用线段树来维护横向的信息,当线段树上某个位置有值的时候,就说明此时这一列上下均有一个黑点,再找到当前纵坐标下最左/右端的两个黑点,求这两个黑点之前线段树区间和就是新增的黑点数量。

具体做法是,从下往上地遍历所有点,如果当前点是某个横坐标下最下方的点,那么就在线段树上给该位置 + 1 +1 +1,如果当前点是某个横坐标下最上方的点,那么就在线段树上给该位置 − 1 -1 −1,这样就保证线段树上有值的位置就是上下都有黑点的位置。

一些细节:横坐标需要离散化、注意独占一纵列的黑点、注意本来上下左右就有黑点的黑点、注意左右本来就有黑点且本身又是纵线最下面的点的黑点。

代码

《取max的初始值设置成0被负数卡了一天且对拍到自闭的故事》

#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=1e5+5;
struct Point{int x,y,val;}pt[M];
struct node{int le,ri,sum;}tree[M<<2];
bool cmpy(Point a,Point b){return a.y==b.y?a.x<b.x:a.y<b.y;}
bool cmpx(Point a,Point b){return a.x==b.x?a.y<b.y:a.x<b.x;}
int n,ans,x[M],tot;
void up(int v){tree[v].sum=tree[ls].sum+tree[rs].sum;}
void build(int v,int le,int ri)
{
    tree[v].le=x[le],tree[v].ri=x[ri];
    if(le==ri)return;
    int mid=le+ri>>1;
    build(ls,le,mid),build(rs,mid+1,ri);
}
void add(int v,int x,int val)
{
    if(val>1)return;
    if(tree[v].le==tree[v].ri){tree[v].sum+=val;return;}
    if(x<=tree[ls].ri)add(ls,x,val);
    else add(rs,x,val);
    up(v);
}
int ask(int v,int le,int ri)
{
    if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].sum;
    int r=0;
    if(le<=tree[ls].ri)r=ask(ls,le,ri);
    if(tree[rs].le<=ri)r+=ask(rs,le,ri);
    return r;
}
void in()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d%d",&pt[i].x,&pt[i].y),x[i]=pt[i].x;
}
void ac()
{
    sort(pt+1,pt+1+n,cmpx);
    for(int i=1;i<=n;++i)
    {
        x[i]=pt[i].x;
        if(pt[i].x!=pt[i-1].x&&pt[i].x!=pt[i+1].x){pt[i].val=2;continue;}
        if(pt[i].x!=pt[i-1].x)pt[i].val=1;
        else if(pt[i].x!=pt[i+1].x)pt[i].val=-1;
    }
    tot=unique(x+1,x+1+n)-x-1;
    build(1,1,tot);
    sort(pt+1,pt+1+n,cmpy);
    for(int i=1,j=1,le,ri;i<=n;++i)
    {
        for(j=i,le=INT_MAX,ri=-INT_MAX;pt[i].y==pt[i+1].y;++i)add(1,pt[i].x,pt[i].val),le=min(le,pt[i].x),ri=max(ri,pt[i].x);
        add(1,pt[i].x,pt[i].val),le=min(le,pt[i].x),ri=max(ri,pt[i].x);
        for(j+=1;j<i;++j)ans-=(!pt[j].val||pt[j].val==1);
        if(le!=ri)ans+=ask(1,le+1,ri-1);
    }
    printf("%d\n",ans+n);
}
int main()
{
    in(),ac();
    //system("pause");
}

标签:ri,le,pt,黑点,白点,Luogu5816,int,CQOI2010
来源: https://blog.csdn.net/ShadyPi/article/details/113661664

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有