poj2464 Brownie Points II 树状数组

Description

Stan and Ollie play the game of Odd Brownie Points. Some brownie points are located in the plane, at integer coordinates. Stan plays first and places a vertical line in the plane. The line must go through a brownie point and may cross many (with the same x-coordinate). Then Ollie places a horizontal line that must cross a brownie point already crossed by the vertical line.
Those lines divide the plane into four quadrants. The quadrant containing points with arbitrarily large positive coordinates is the top-right quadrant.

The players score according to the number of brownie points in the quadrants. If a brownie point is crossed by a line, it doesn't count. Stan gets a point for each (uncrossed) brownie point in the top-right and bottom-left quadrants. Ollie gets a point for each (uncrossed) brownie point in the top-left and bottom-right quadrants.

Stan and Ollie each try to maximize his own score. When Stan plays, he considers the responses, and chooses a line which maximizes his smallest-possible score.

Input

Input contains a number of test cases. The data of each test case appear on a sequence of input lines. The first line of each test case contains a positive odd integer 1 < n < 200000 which is the number of brownie points. Each of the following n lines contains two integers, the horizontal (x) and vertical (y) coordinates of a brownie point. No two brownie points occupy the same place. The input ends with a line containing 0 (instead of the n of a test).

Output

For each input test, print a line of output in the format shown below. The first number is the largest score which Stan can assure for himself. The remaining numbers are the possible (high) scores of Ollie, in increasing order.

Sample Input

11
3 2
3 3
3 4
3 6
2 -2
1 -3
0 0
-3 -3
-3 -2
-3 -4
3 -7
0

Sample Output

Stan: 7; Ollie: 2 3;

  一个平面有一些点,stan先竖着画一条线(必须经过一个点),ollie横着画一条线(必须经过stan画的线上的一个点),stan得分是一三象限的点数,ollie得分是二四象限的点数,在线上的不算。ollie要在自己得分最高的情况下让stan得分最少,输出stan得最低分最高的情况下的最低分,和stan得到这个分数时ollie的所有可能得分。

  参考了cxlove大神的,用两个树状数组表示竖线的左边和右边,对y离散化。一开始把所有点都加到右边的树状数组,竖线从左到右扫过去,每次把在竖线上的点从右边删除,算出在这条竖线上每个点画横线的情况a和b,更新答案:如果b比当前的ollie更大,把a和b都赋值成当前值,如果b等于当前ollie值,就把stan更新到min(stan,a)。这条线所有点更新完后的stan如果小于当前答案就把存ollie的vector清空,如果等于当前答案的话就把ollie存到vector里。

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MAXN 200010
#define MAXM 2000010
#define MAXNODE MAXN*4
#define MOD 999983
typedef long long LL;
using namespace std;
int N,l[MAXN],r[MAXN],y[MAXN];
vector<int> Ollie;
struct Point{
    int x,y;
    bool operator < (const Point& a) const{
        return x<a.x;
    }
}p[MAXN];
int lowbit(int x){
    return x&(-x);
}
void update(int *c,int i,int v){
    while(i<=N){
        c[i]+=v;
        i+=lowbit(i);
    }
}
int sum(int *c,int i){
    int ret=0;
    while(i>0){
        ret+=c[i];
        i-=lowbit(i);
    }
    return ret;
}
int main(){
    freopen("in.txt","r",stdin);
    while(scanf("%d",&N)!=EOF&&N){
        for(int i=0;i<N;i++){
            scanf("%d%d",&p[i].x,&p[i].y);
            y[i]=p[i].y;
        }
        sort(y,y+N);
        sort(p,p+N);
        int n=unique(y,y+N)-y;
        memset(l,0,sizeof(l));
        memset(r,0,sizeof(r));
        for(int i=0;i<N;i++) update(r,lower_bound(y,y+n,p[i].y)-y+1,1);
        int Stan=-1,e;
        Ollie.clear();
        for(int i=0;i<N;i++) if(!i||p[i].x!=p[i-1].x){
            update(r,lower_bound(y,y+n,p[i].y)-y+1,-1);
            e=i;
            for(int j=i+1;j<N&&p[j].x==p[j-1].x;j++){
                update(r,lower_bound(y,y+n,p[j].y)-y+1,-1);
                e=j;
            }
            int stan=INF,ollie=-1;
            for(int j=i;j<=e;j++){
                int pos=lower_bound(y,y+n,p[j].y)-y+1;
                int a=sum(l,pos-1)+sum(r,n)-sum(r,pos),b=sum(r,pos-1)+sum(l,n)-sum(l,pos);
                if(b==ollie) stan=min(stan,a);
                else if(b>ollie){
                    stan=a;
                    ollie=b;
                }
            }
            if(stan>Stan){
                Stan=stan;
                Ollie.clear();
            }
            if(stan==Stan) Ollie.push_back(ollie);
            for(int j=i;j<=e;j++) update(l,lower_bound(y,y+n,p[j].y)-y+1,1);
        }
        printf("Stan: %d; Ollie:",Stan);
        sort(Ollie.begin(),Ollie.end());
        n=unique(Ollie.begin(),Ollie.end())-Ollie.begin();
        for(int i=0;i<n;i++) printf(" %d",Ollie[i]);
        puts(";");
    }
    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值