tju 4071 2D Birds-Shooting Game 线段树+最长上升子序列

4071.   2D Birds-Shooting Game
Time Limit: 2.0 Seconds   Memory Limit: 65536K
Total Runs: 292   Accepted Runs: 75



There are N birds in a 2D space, let x and y denote their coordinate in each dimension.
As an excellent shooter, you can shoot down all the birds in the 2D space. But you think that's too cruel.
In order to make the shooting procedure more interesting, you come up with a rule:
At the beginning, you can choose any bird to shoot.
Afterwards, you can only shoot the bird whose coordinate is not smaller than the previous one in each dimension.
For example, if you want to shoot three birds a, b and c then the following relationship must hold:
xa≤xb, ya≤yb, xb≤xc, yb≤yc.
With this rule and coordinates of all the N birds, can you figure out how many birds you can shoot as many as possible?

Input

First line will be a positive integer T indicating the test case number. Following there are T (1≤T≤10) test cases.
Each test case begins with a positive integer N (1≤N≤100000), the number of birds.
Then following N lines with two positive integers x and y (1≤x,y≤100000), which are the coordinates of each bird (you can assume no two birds have the same coordinates).

Output

For each test case output only one integer representing the maximal number of birds you can shoot.

Sample Input

2
3
1 1
2 2
3 3
3
1 1
2 3
3 2

Sample Output

3
2

题意:每次打鸟必须比上次比上次高,问最多打多少鸟

题目分析:线段树水过去,有o(n)的算法,在我的博客中能找到,这道题看代码把

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#define MAX 100007

using namespace std;

int t,n;

struct Bird
{
    int x,y;
    bool operator < ( const Bird & a ) const 
    {
        if ( x == a.x ) return y < a.y;
        return x < a.x;
    }
}a[MAX];

struct Tree
{
    int l,r,maxn;
}tree[(MAX+1)<<2];

void build ( int u , int l , int r )
{
    tree[u].l = l , tree[u].r = r;
    tree[u].maxn = 0;
    if ( l == r ) return;
    int mid = l + r >> 1;
    build ( u<<1 , l , mid );
    build ( u<<1|1 , mid+1 , r );
}

void push_up ( int u )
{
    tree[u].maxn = max ( tree[u<<1].maxn , tree[u<<1|1].maxn );
}

void update ( int u , int x , int v )
{
    int l = tree[u].l , r = tree[u].r;
    if ( l == r )
    {
        tree[u].maxn = max ( v , tree[u].maxn );
        return;
    }
    int mid = l + r >>1;
    if ( x > mid ) update ( u<<1|1 , x , v );
    else update ( u<<1 , x , v );
    push_up ( u );
}

int query ( int u , int left , int right )
{
    int l = tree[u].l , r = tree[u].r;
    if ( left <= l && r <= right )
        return tree[u].maxn;
    int mid = l + r >> 1;
    int maxn = 0;
    if ( left <= mid && l <= right ) maxn = max ( maxn , query ( u<<1 , left  , right ) );
    if ( left <= r && right > mid ) maxn = max ( maxn , query ( u<<1|1 , left , right ) );
    return maxn;
}

int main ( )
{
    scanf ( "%d" , &t );
    while ( t-- )
    {
        scanf ( "%d" , &n );
        for ( int i = 1 ; i <= n ; i++ )
            scanf ( "%d%d" , &a[i].x , &a[i].y );
        sort ( a+1 , a+n+1 );
        build ( 1 , 1 , MAX-2 );
        int ans = 0;
        for ( int i = 1 ; i <= n ; i++ )
        {
           int num = query ( 1 , 1 , a[i].y ) + 1;
           ans = max ( ans , num );
           update ( 1 , a[i].y , num );
        }    
        printf ( "%d\n" , ans ); 
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值