1. 程式人生 > >【BZOJ1818】[CQOI2010]內部白點(樹狀陣列,掃描線)

【BZOJ1818】[CQOI2010]內部白點(樹狀陣列,掃描線)

【BZOJ1818】[CQOI2010]內部白點(樹狀陣列,掃描線)

題面

BZOJ

題解

不難發現\(-1\)就是在搞笑的。
那麼對於每一行,我們顯然可以處理出來最左和最右的點,那麼等價於我們在橫著的方向上得到了若干條線段,同理,在豎直方向上也得到了若干條線段,那麼最終的答案就是這些線段的交點個數加上原先就有的白點個數,再減去交點上的黑點數目。
直接離散沒有任何問題,那麼直接掃描線計算即可。
程式碼有點醜。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 100100
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
struct Node{int x,y;}p[MAX];
bool operator<(Node a,Node b){if(a.y^b.y)return a.y<b.y;return a.x<b.x;}
bool cmp(Node a,Node b){if(a.x^b.x)return a.x<b.x;return a.y<b.y;}
struct Line{int x,y,v;}X[MAX<<1];
bool operator<(Line a,Line b){if(a.x^b.x)return a.x<b.x;return a.y<b.y;}
int Sx[MAX],tx,Sy[MAX],ty;
int n,ans,tot,c[MAX],v[MAX];
int lb(int x){return x&(-x);}
void add(int x,int w){while(x<=n)c[x]+=w,x+=lb(x);}
int getsum(int x){int s=0;while(x)s+=c[x],x-=lb(x);return s;}
int main()
{
    n=read();ans=n;
    for(int i=1;i<=n;++i)p[i].x=read(),p[i].y=read();
    for(int i=1;i<=n;++i)Sx[++tx]=p[i].x,Sy[++ty]=p[i].y;
    sort(&Sx[1],&Sx[tx+1]);tx=unique(&Sx[1],&Sx[tx+1])-Sx-1;
    sort(&Sy[1],&Sy[ty+1]);ty=unique(&Sy[1],&Sy[ty+1])-Sy-1;
    for(int i=1;i<=n;++i)p[i].x=lower_bound(&Sx[1],&Sx[tx+1],p[i].x)-Sx;
    for(int i=1;i<=n;++i)p[i].y=lower_bound(&Sy[1],&Sy[ty+1],p[i].y)-Sy;
    sort(&p[1],&p[n+1]);
    for(int i=1,j;i<=n;i=j+1)
    {
        j=i;while(j<n&&p[i].y==p[j+1].y)++j;
        X[++tot]=(Line){p[i].x,p[j].y,1};
        X[++tot]=(Line){p[j].x+1,p[j].y,-1};
    }
    sort(&p[1],&p[n+1],cmp);sort(&X[1],&X[tot+1]);
    for(int i=1,j,pos=1;i<=n;i=j+1)
    {
        j=i;while(j<n&&p[i].x==p[j+1].x)++j;
        int l=p[i].y,r=p[j].y,x=p[i].x;
        while(pos<=tot&&X[pos].x<=x)
        {
            int xx=X[pos].y;v[xx]+=X[pos].v;
            if(!v[xx])add(X[pos].y,-1);
            else if(v[xx]==1)add(X[pos].y,1);
            ++pos;
        }
        ans+=getsum(r)-getsum(l-1);
        for(int k=i;k<=j;++k)if(v[p[k].y])ans-=1;
    }
    printf("%d\n",ans);
    return 0;
}