poj2464 线段树扫描线

由于这几天刚好有事,这题目拖了好几天,今天总算静下心来搞定了。题目并不难,只是有点繁琐,而且要注意细节。

简要思路:

先把数据离散化,同时记录每一个X左右边有多少,X有多少,Y同理;

然后按先X再Y从小到大排序,再来扫描,用线段树记录区间里点的个数。

然后推出四个象限的点的个数,麻烦的事来了,坐标上的点怎么去掉,开了cntx,cnty记录每个X,Y坐标询问次数,然后就很简单了。

最后把第二个人的结果排序再去重就OK了;


ACcode:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::sort;

const int nsize=222222;

struct Point
{
    int x,y;
} pot[nsize];

int n,k,nx,ny,maxs;
int maxy[nsize],num[nsize<<2];
int lft[nsize],rgt[nsize];
int up[nsize],down[nsize];
int curx[nsize],cury[nsize];
int *px[nsize],*py[nsize];
int cntx[nsize],cnty[nsize];

int Max(int a1,int a2)
{
    return a1>a2?a1:a2;
}

int Min(int a1,int a2)
{
    return a1<a2?a1:a2;
}

bool cmp1(int *a1,int *a2)
{
    return *a1<*a2;
}

bool cmp2(Point a1,Point a2)
{
    if (a1.x==a2.x) return a1.y<a2.y;
    return a1.x<a2.x;
}

void leave()
{
    int i,tx,ty;
    sort(px,px+n,cmp1);
    sort(py,py+n,cmp1);
    nx=ny=1;
    tx=*px[0],ty=*py[0];
    *px[0]=*py[0]=1;
    lft[0]=lft[1]=0;
    down[0]=down[1]=0;
    for (i=1; i<n; i++)
    {
        if (*px[i]!=tx)
        {
            tx=*px[i];
            curx[nx]=i-lft[nx];
            rgt[nx]=n-i;
            lft[++nx]=i;
        }
        *px[i]=nx;

        if (*py[i]!=ty)
        {
            ty=*py[i];
            cury[ny]=i-down[ny];
            up[ny]=n-i;
            down[++ny]=i;
        }
        *py[i]=ny;
    }
    rgt[nx]=up[ny]=0;
    curx[nx]=n-lft[nx];
    cury[ny]=n-down[ny];
}

int query(int rt,int l,int r,int L,int R)
{
    if (L<=l&&r<=R) return num[rt];
    int m=(l+r)>>1,ans=0;
    if (L<=m) ans+=query(rt<<1,l,m,L,R);
    if (R>m)  ans+=query(rt<<1|1,m+1,r,L,R);
    return ans;
}

void PushUp(int rt)
{
    num[rt]=num[rt<<1]+num[rt<<1|1];
}

void update(int rt,int l,int r,int p)
{
    if (l==r)
    {
        num[rt]++;
        return ;
    }
    int m=(l+r)>>1;
    if (p<=m) update(rt<<1,l,m,p);
    else update(rt<<1|1,m+1,r,p);
    PushUp(rt);
}

void solve()
{
    int i,tx,ty;
    int lu,ld,ru,rd;
    int mins=nsize,may=-1;
    maxs=0,k=0;
    sort(pot,pot+n,cmp2);
    memset(num,0,sizeof(num));
    memset(cntx,0,sizeof(cntx));
    memset(cnty,0,sizeof(cnty));
    for (i=0; i<n; i++)
    {
        tx=pot[i].x;
        ty=pot[i].y;
        lu=query(1,1,ny,ty+1,ny);
        ld=lft[tx]-lu-cnty[ty];
        rd=down[ty]-ld-cntx[tx];
        ru=up[ty]-lu-(curx[tx]-cntx[tx]-1);
        //      ru=n-curx[tx]-cury[ty]+1-ld-rd-lu;
        mins=Min(mins,ld+ru);
        may=Max(may,lu+rd);
        update(1,1,ny,ty);
        cntx[tx]++;
        cnty[ty]++;
        if (i==(n-1)||(tx!=pot[i+1].x))
        {
            if (maxs<mins)
            {
                maxs=mins;
                maxy[0]=may;
                k=1;
            }
            else if (maxs==mins)
                maxy[k++]=may;
            mins=nsize,may=-1;
        }

    }
    printf("Stan: %d; Ollie:",maxs);
    sort(maxy,maxy+k);
    for (ty=i=1; i<k; i++)
        if (maxy[i]!=maxy[i-1]) maxy[ty++]=maxy[i];
    for (i=0; i<ty; i++) printf(" %d",maxy[i]);
    puts(";");
}

int main()
{
    int i;
    while (scanf("%d",&n)&&n)
    {
        for (i=0; i<n; i++)
        {
            scanf("%d %d",&pot[i].x,&pot[i].y);
            px[i]=&pot[i].x,py[i]=&pot[i].y;
        }
        leave();
        solve();
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值