POJ 2352 Stars

题意:按y递增的顺序给出n颗星星的坐标(y相等则x递增),每个星星的等级,等于在它左边且在它下边(包括水平和垂直方向)的星星的数量,求出等级为0到n-1的星星分别有多少个


分析:树状数组或者线段树。


//416K	141MS  树状数组
#include <stdio.h>
#include <string.h>
#define MAX 32010
int c[MAX] ;        //树状数组  
int lev[MAX] ;      //level[X] 指的是 不超过当前点的高度和不在当前点右边的点的个数为x 的这些点的个数

int Low_Bit ( int x )
{
    return x & ( -x ) ;
}

void Update ( int x )           //插入一个 x 就要更新 x 的祖先们   
{
    while ( x < MAX )
    {
        c[x] ++ ;
        x += Low_Bit ( x ) ;
    }
}

int Get_Sum ( int x )       //求得 x 的等级 ,也就是 x 前面有多少个和x同列或者靠左的点       
{
                             //因为输入的时候,y是递增的,所以不用考虑y   
    int sum ;
    sum = 0 ;
    while ( x > 0 )
    {
        sum += c[x] ;
        x -= Low_Bit ( x ) ;        //x 前面的一棵子树的根的下标   
    }
    return sum ;
}

int
main ( )
{
    int n ;
    while ( EOF != scanf ("%d" , & n ) )
    {
        memset ( lev , 0 , sizeof ( lev ) ) ;
        memset ( c , 0 , sizeof ( c ) ) ;
        int i ;
        for ( i = 1 ; i <= n ; i ++ )
        {
            int x , y ;
            scanf ("%d%d" , & x , & y ) ;
            x ++ ;
            int index ;
            index = Get_Sum ( x ) ;
            lev[index] ++ ;
            Update ( x ) ;
        }
        for ( i = 0 ; i < n ; i ++ )
        {
            printf ("%d\n" , lev[i] ) ;
        }
    }
    return 0 ;
}
线段树的做法是,每插入一颗星星(设其横坐标为x),将区间[x,32000]加1,即后面的星星的层数加1,这样后面的星星调用Query(x)便可返回层数.


//1000K	219MS
#include <stdio.h>
#define L(X) ((X)<<1)
#define R(X) ((X<<1)|1)
#define MID(X,Y) ((X+Y)>>1)
#define N 32005
#define DEBUG puts("Hi") ;
int lev[N] ;
struct node
{
    int left , right ;
    int val ;
}node[N*4];

void Creat_Tree ( int const left , int const right , int const n )
{
    node[n].left = left ;
    node[n].right = right ;
    node[n].val = 0 ;
    if ( left < right )
    {
        int mid ;
        mid = MID (left , right ) ;
        Creat_Tree ( left , mid , L(n) ) ;
        Creat_Tree ( mid + 1 , right , R(n) ) ;
    }
}

void Update ( int const left , int const right , int const n )
{
    if ( node[n].left == left && node[n].right == right )
    {
        node[n].val ++ ;
    }
    else
    {
        int mid ;
        mid = MID ( node[n].left , node[n].right ) ;
        if ( right <= mid )
        {
            Update ( left , right , L(n) ) ;
        }
        else if ( left > mid )
        {
            Update ( left , right , R(n) ) ;
        }
        else
        {
            Update ( left , mid , L(n) ) ;
            Update ( mid + 1 , right , R(n) ) ;
        }
    }
}

int Query ( int x , int n )
{
    if ( node[n].right == node[n].left )
    {
        return node[n].val ;
    }
    else
    {
        int mid ;
        mid = MID ( node[n].left , node[n].right ) ;
        if ( x <= mid  )
        {
            return node[n].val + Query( x , L(n) ) ;
        }
        else
        {
            return node[n].val + Query( x , R(n) ) ;
        }
    }
}

int
main ( )
{
    int n ;
    scanf ("%d" , & n ) ;
    Creat_Tree ( 0 , N , 1 ) ;
    int i ;
    for ( i = 0 ; i < n ; i ++ )
    {
        int x , y ;
        scanf ("%d%d" , & x , & y ) ;
        int index ;
        index = Query ( x , 1 ) ;
        lev[index] ++ ;
        Update ( x , N , 1 ) ;
    }
    for ( i = 0 ; i < n ; i ++ )
    {
        printf ("%d\n" , lev[i] ) ;
    }
    return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值