POJ_2464 Brownie Points II 线段树

http://poj.org/problem?id=2464

题意:

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

思路:

这题其实也数星星那题基本思路是一样的,题目的关键就是要求出在给定一个点之后,如何求出其四个象限内的点的个数。求出之后依次枚举最大值的出现位置和ollie可能的值。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#define MIN(a,b) ( (a)>(b)?(b):(a) )
int N  ;
const int MAXN = 200010 ;

struct Node{
    int x ,y ;
}p[MAXN] ;
bool comp(Node n1 , Node n2){
    if(n1.x == n2.x )   return n1.y > n2.y ;
    else                return n1.x < n2.x ;
}
int x[MAXN] , y[MAXN] ;
int xn , yn  ;
int xnum[MAXN] ,ynum[MAXN] ;
int xsum[MAXN] , ysum[MAXN] ;


int findx(int v , int l , int r){
    while(l<r){
        int mid = (l + r) >> 1 ;
        if( x[mid] < v )    l = mid + 1;
        else        r = mid ;
    }
    return l ;
}
int findy(int v , int l ,int r){
    while( l<r ){
        int mid = (l + r)>> 1 ;
        if( y[mid] < v )    l = mid + 1 ;
        else    r = mid ;
    }
    return l ;
}

int C[MAXN] ;

int lowbit(int x){
    return ( x&(x^(x-1)) ) ;
}
void add(int n){
    while( n<=N ){
        C[n]++ ;
        n += lowbit(n);
    }
}
int sum(int n){
    int res = 0 ;
    while( n>=1 ){
        res += C[n] ;
        n -= lowbit(n) ;
    }
    return res ;
}
int stan[MAXN] ;
std::vector<int> ol[MAXN] ;

void sovle(){
    std::sort( p+1, p+N+1 ,comp);
    memset( C , 0 ,sizeof(C) );
    for(int i=1;i<=N;i++){
        stan[i] = N + 1 ;
        ol[i].clear() ;
    }
    for(int i=1;i<=N;i++){
        int x = findx( p[i].x , 1, xn );
        int y = findy( p[i].y , 1 ,yn );
        add(y) ;
        int a = sum(y-1) ;
        int b = N - ysum[y] - ( i - sum(y) ) ;
        int c = N - a - b - xnum[x] - ynum[y] + 1 ;
        stan[x] = MIN( stan[x] , a + b);
        ol[x].push_back( c ) ;
    }
    int _max = -1 ;
    for(int i=1;i<=xn;i++){
        if( _max < stan[i] )    _max = stan[i] ;
    }
    bool is_ok[MAXN] ;
    memset(is_ok , 0 ,sizeof(is_ok));
    for(int i=1;i<=xn;i++){
        if( _max == stan[i] ) {
            for(int j=0;j<ol[i].size();j++)
                is_ok[ ol[i][j] ] = 1 ;
        }
    }
    printf("Stan: %d; Ollie:",_max);
    for(int i=0;i<=N;i++)
        if(is_ok[i])    printf(" %d",i);
    printf(";\n");
}

int main(){
    while( scanf("%d",&N) && N ){
        for(int i=1;i<=N;i++){
            scanf("%d%d",&p[i].x , &p[i].y );
            x[i] = p[i].x ; y[i] = p[i].y ;
        }
        std::sort(x+1 , x+N+1);
        std::sort(y+1 , y+N+1);
        xn = yn = 2 ;
        for(int i=2;i<=N;i++){
            if( x[i] != x[i-1] )   x[xn++] = x[i] ;
        }
        for(int i=2;i<=N;i++){
            if( y[i] != y[i-1]  ) y[yn++] = y[i] ;
        }
        xn -- ; yn -- ;
        memset(xnum , 0 ,sizeof(xnum) );
        memset(ynum , 0 ,sizeof(ynum) );

        for(int i=1;i<=N;i++){
            int s = findx(p[i].x , 1 ,xn ) ;
            xnum[s] ++ ;
        }
        xsum[0] = 0 ;
        for(int i=1;i<=xn;i++)
            xsum[i] = xsum[i-1] + xnum[i] ;
        for(int i=1;i<=N;i++){
            int s = findy(p[i].y , 1 ,yn );
            ynum[s] ++ ;
        }
        ysum[0] = 0 ;
        for(int i=1;i<=yn;i++){
            ysum[i] = ysum[i-1] + ynum[i] ;
        }
        sovle() ;
    }
    return 0 ;
}


你可能感兴趣的:(POJ_2464 Brownie Points II 线段树)