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

Posted dukelv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了B1818 [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

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(int i = a;i <= n;i++)
#define lv(i,a,n) for(int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 1 << 30;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < 0 || c > 9)
        if(c == -) op = 1;
    x = c - 0;
    while(c = getchar(), c >= 0 && c <= 9)
        x = x * 10 + c - 0;
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar(-), x = -x;
    if(x >= 10) write(x / 10);
    putchar(0 + x % 10);
}
struct point
{
    int x,y;
}a[100010];
struct seg
{
    int k,x,y,r;
}s[1000010];
int n;
int hsh[100010],cnt = 0;
int tr[100010],ans = 0;
bool cmp1(point a,point b)
{
    if(a.x == b.x)
    return a.y < b.y;
    else
    return a.x < b.x;
}
bool cmp2(point a,point b)
{
    if(a.y == b.y)
    return a.x < b.x;
    else
    return a.y < b.y;
}
bool cmp3(seg a,seg b)
{
    if(a.y == b.y)
    return a.k < b.k;
    else
    return a.y < b.y;
}
int find(int x)
{
    int l = 1,r = n,mid;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(hsh[mid] < x)
        l = mid + 1;
        else if(hsh[mid] > x)
        r = mid - 1;
        else return mid;
    }
}
void insert(int k,int l,int r,int t)
{
    if(!k)
    {
        s[++cnt].x = find(l);
        s[cnt].r = find(r);
        s[cnt].y = t;
    }
    else
    {
        s[++cnt].x = find(t);
        s[cnt].y = l;
        s[cnt].k = 1;
        s[++cnt].x = find(t);
        s[cnt].y = r;
        s[cnt].k = -1;
    }
}
int lowbit(int x)
{
    return x & -x;
}
void build()
{
    sort(a + 1,a + n + 1,cmp1);
    duke(i,2,n)
    {
        if(a[i].x == a[i - 1].x)
        insert(1,a[i - 1].y,a[i].y,a[i].x);
    }
    sort(a + 1,a + n + 1,cmp2);
    duke(i,2,n)
    {
        if(a[i].y == a[i - 1].y)
        insert(0,a[i - 1].x,a[i].x,a[i].y);
    }
}
void update(int x,int y)
{
    while(x <= n)
    {
        tr[x] += y;
        x += lowbit(x);
    }
}
int ask(int x)
{
    int s = 0;
    while(x)
    {
        s += tr[x];
        x -= lowbit(x);
    }
    return s;
}
void work()
{
    duke(i,1,cnt)
    {
        if(!s[i].k)
        ans += ask(s[i].r - 1) - ask(s[i].x);
        else
        update(s[i].x,s[i].k);
    }
}
int main()
{
    read(n);
    duke(i,1,n)
    {
        read(a[i].x);
        read(a[i].y);
        hsh[i] = a[i].x;
    }
    sort(hsh + 1,hsh + n + 1);
    build();
    sort(s + 1,s + cnt + 1,cmp3);
    work();
    printf("%d
",ans + n);
    return 0;
}
/*
4
0 2
2 0
-2 0
0 -2
*/

 

以上是关于B1818 [Cqoi2010]内部白点 树状数组的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1818 [CQOI 2010] 内部白点 - 扫描线 - 树状数组

1818: [Cqoi2010]内部白点

1818: [Cqoi2010]内部白点

BZOJ1818: [Cqoi2010]内部白点

bzoj 1818: [Cqoi2010]内部白点

bzoj 1818: [Cqoi2010]内部白点