Poj 2464 Brownie Points II(平面两条垂直的先划分成四个象限,一三象限和二四象限各有多少个)

传送门:Poj 2464 Brownie Points II


题意:在平面直角坐标系中给你N个点,stan和ollie玩一个游戏,首先stan在竖直方向上画一条直线,该直线必须要过其中的某个点,然后ollie在水平方向上画一条直线,该直线的要求是要经过一个stan之前画过的点。这时候平面就被分割成了四块,两个人这时候会有一个得分,stan的得分是平面上第1、3象限内的点的个数,ollie的得分是平面上第2、4象限内的点的个数,在统计的时候在所画线上的点都不计算在内。求最终stan使得自己的最差得分最高,并且输出此时ollie的得分。
(N<=2e5)


思路:
我们可以枚举分界线,分界线左右两边各维护一个线段树
枚举分界线上的每个点的y值,那么1,3象限对应的y值也就能确定了
那么就可以确定在1,3象限的点的个数,对应的2,4象限用vector存起来


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
const int N=2e5+10;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct Point{
    int x,y;
}a[N];
int t[N];
int sumv[2][N*4],Count[N],x[N];
vector<int>tmp;

bool cmp(Point u,Point v){
    if(u.x!=v.x)
        return u.x<v.x;
    return u.y<v.y;
}

int pos,d;

void pushup(int rt,int flag){
    sumv[flag][rt]=sumv[flag][rt<<1]+sumv[flag][rt<<1|1];
}

void update(int l,int r,int rt,int flag){
    if(l==r){
        sumv[flag][rt]+=d;
        return ;
    }
    int m=(l+r)>>1;
    if(pos<=m)  update(lson,flag);
    else    update(rson,flag);
    pushup(rt,flag);
}

int L,R;

int query(int l,int r,int rt,int flag){
    if(L<=l&&R>=r)
        return sumv[flag][rt];
    int m=l+r>>1,Ans=0;
    if(L<=m)    Ans+=query(lson,flag);
    if(R>m)     Ans+=query(rson,flag);
    return Ans;
}

int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        if(n==0)    break;
        tmp.clear();
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i].x,&a[i].y);
            t[i]=a[i].y,x[i]=a[i].x;
        }
        sort(a+1,a+n+1,cmp);
        sort(t+1,t+n+1);
        sort(x+1,x+n+1);
        int m=unique(t+1,t+n+1)-t-1,mm=unique(x+1,x+n+1)-x-1;
        memset(sumv,0,sizeof(sumv));
        memset(Count,0,sizeof(Count));  //每一行有多少个
        for(int i=1;i<=n;i++){  //将点全部插入到第二颗
            pos=lower_bound(t+1,t+m+1,a[i].y)-t,d=1;
            Count[pos]++;
            update(1,n,1,1);
        }
        int st=1,Stan=0;
        for(int i=1;i<=mm;i++){
            int ed=st;
            while(st<=n&&a[st].x==x[i]){    //同一列一起处理
                pos=lower_bound(t+1,t+m+1,a[st].y)-t,d=-1;
                update(1,n,1,1);
                ++st;
            }
            int Ollie=-1,stan=-1;
            for(int j=ed;j<st;j++){ //枚举取哪一个点
                int num=lower_bound(t+1,t+m+1,a[j].y)-t,Ans=0;
                while(j-1>=ed&&a[j].y==a[j-1].y){

                }
                L=num+1,R=m;
                if(L<=R)    Ans+=query(1,n,1,1);
                L=1,R=num-1;
                if(L<=R)    Ans+=query(1,n,1,0);
                if(n-(st-ed)-Count[num]+1-Ans>Ollie)
                    stan=Ans,Ollie=n-(st-ed)-Count[num]+1-Ans;
                else  if(n-(st-ed)-Count[num]+1-Ans==Ollie)
                    stan=min(stan,Ans);
            }
            if(stan>Stan){
                tmp.clear();
                Stan=stan;
            }
            if(stan==Stan)
                tmp.push_back(Ollie);
            for(int j=ed;j<st;j++){
                int num=lower_bound(t+1,t+m+1,a[j].y)-t;
                pos=num,d=1;
                update(1,n,1,0);
            }
        }
        sort(tmp.begin(),tmp.end());
        vector<int>::iterator iter=unique(tmp.begin(),tmp.end());
        tmp.erase(iter,tmp.end());
        printf("Stan: %d; Ollie:",Stan);
        for(int i=0;i<tmp.size();i++)  printf(" %d",tmp[i]);
        printf(";\n");
    }
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值