SGU 521 North-East ( 二维LIS 线段树优化 )

521. "North-East"

Time limit per test: 0.5 second(s)
Memory limit: 262144 kilobytes
input: standard
output: standard


The popular music band of international fame "North-East" is coming to Berland! This news has spread all over the country, so numerous fans are now ready to rush and buy all the tickets!

At present the fans still don't know in which cities the band plans to give concerts. The only thing is known at the moment is that the band will visit several cities, and as their name says, they will strictly move north and east when going to the next city. In other words when the band moves from city i to city j, city j is always located northward and eastward of the city i.

It's also known that the tour is planned in such a way that the maximum possible number of cities will be visited. The musicians refuse to reveal other details. As you know, fans always get ready for the arrival of their idols, so they would appreciate any single detail about possible movements of their favorite musicians.

Your task is to help the fans and find two lists of cities — A and B. The first list A should contain the cities, which the band might visit during the tour. The second list B should contain the cities, which the band will have to visit for sure during the tour.

Input

The first line of input contains a single integer n (1 ≤ n ≤ 105) — amount of cities in the country. The following n lines contain coordinates of the cities. Each line contains a pair of integersxiyi (-106 ≤ xiyi ≤ 106) — the coordinates of the i-th city. Ox axis is directed west-to-east, and Oy axis — south-to-north. No two given cities will be located at the same point.

Output

Print the required list A to the first line of output and B to the second line. Each list should start with the amount of cities in it, followed by the indices of cities in increasing order. Cities are numbered from 1 to n.

Example(s)
sample input
sample output
5
3 2
1 1
5 5
2 3
4 4
5 1 2 3 4 5
3 2 3 5

 

sample input
sample output
5
1 1
10 10
5 6
10 1
6 5
4 1 2 3 5
2 1 2

 

 

题意是可以从某个点出发,走向 x , y 都严格增大的点走 , 问那些点可能在最长路径上 ,那些点必定会经过

 

用 dp[0][i] 表示点i 作为右端点的最长路 , dp[1][i] 表示点i 作为左端点的最长路 。

再判一下 dp[0][i] + dp[1][i]  是否跟最大值相等 , 就可知道它是否第一类点。

而第二类点直接用一个cnt数组记录一下数字的出现次数是否唯一即可判断 ~

#include <bits/stdc++.h>
using namespace std ;
const int N = 200020 ;

int n ;

struct SegTree {
    #define root 1,n+10,1
    #define lr rt<<1
    #define rr rt<<1|1
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    int mx[N<<2]  ;

    void Up( int rt ) {
        mx[rt] = max( mx[lr] , mx[rr] ) ;
    }

    void Build( int l , int r , int rt ) {
        mx[rt] = 0 ;
        if( l == r ) return ;
        int mid = ( l+r ) >> 1 ;
        Build(lson),Build(rson) ;
    }

    void Update( int l , int r , int rt , int x , int v ) {
        if( l == r ) { mx[rt] = v ; return ; }
        int mid = (l+r)>>1;
        if( x <= mid ) Update( lson , x , v );
        else Update( rson , x , v);
        Up(rt);
    }

    int Query( int l , int r , int rt , int L , int R ) {
        if( l == L && r == R ) return mx[rt] ;
        int mid = (l+r) >> 1 ;
        if( R <= mid ) return Query( lson , L , R ) ;
        else if( L > mid ) return Query( rson , L , R ) ;
        else return max( Query( lson , L , mid ) , Query( rson , mid + 1 , R ) ) ;
    }
} T;

struct node {  int x , y , id ; } e[N] ;

inline bool cmp1( const node &a , const node &b ) {
    if( a.x != b.x ) return a.x < b.x ;
    else return a.y < b.y ;
}

inline bool cmp2( const node &a , const node &b ) {
    if( a.x != b.x ) return a.x > b.x ;
    else return a.y > b.y ;
}


map<int,int>idx;
vector<int>a;
int S[N] , top ;

vector<int> ans1 , ans2 ;
int cnt[N] , dp[2][N] ;


void Doit( int k , int p ) {
    for( int i = top - 1 ; i >= 0 ; --i ) {
        int id = idx[ e[p].y ] ;
        dp[k][ e[p].id ] = S[i] ;
        T.Update( root , id , S[i] );
        p-- ;
    }
}


void Gao() {

    memset( dp , 0 , sizeof dp ) ;
    memset( cnt , 0 , sizeof cnt ) ;

    sort( e + 1 , e + n + 1 , cmp1 ) ;
    T.Build( root ) ; top = 0 ;
    for( int i = 1 ; i <= n ; ++i ) {
        int id = idx[ e[i].y ] ;
        if( i == n || e[i].x != e[i+1].x ) {
            S[top++] = T.Query( root , 1 , id - 1 ) + 1 ;
            Doit( 0 , i );
            top = 0 ;
        } else {
            S[top++] = T.Query( root , 1 , id - 1 ) + 1 ;
        }
    }
    sort( e + 1 , e + n + 1 , cmp2 ) ;
    T.Build( root ) ; top = 0 ;
    for( int i = 1 ; i <= n ; ++i ) {
        int id =  idx[ e[i].y ] ;
        if( i == n || e[i].x != e[i+1].x ) {
            S[top++] = T.Query( root , id + 1 , n + 10 ) + 1 ;
            Doit( 1 , i );
            top = 0 ;
        } else {
            S[top++] = T.Query( root , id + 1 , n + 10 ) + 1 ;
        }
    }

//    for( int i = 1 ; i <= n ; ++i ) cout << e[i].id << ' ' << dp[0][ e[i].id ] << ' ' << dp[1][ e[i].id ] << endl ;

    ans1.clear() , ans2.clear() ;
    int len = 0 ;
    for( int i = 1 ; i <= n ; ++i ) len = max( len , dp[0][i] + dp[1][i] ) ;
    for( int i = 1 ; i <= n ; ++i ) if( dp[0][ e[i].id ] + dp[1][ e[i].id ] == len ) ans1.push_back( e[i].id ) , cnt[ dp[0][ e[i].id ] ]++ ;
    for( int i = 1 ; i <= n ; ++i ) if( dp[0][ e[i].id ] + dp[1][ e[i].id ] == len && cnt[ dp[0][e[i].id] ] == 1 ) ans2.push_back( e[i].id ) ;
}

void Output() {
    sort( ans1.begin() , ans1.end() ) , sort( ans2.begin() , ans2.end() ) ;
    printf("%d",ans1.size()); for( int i = 0 ; i < ans1.size() ; ++i ) printf(" %d",ans1[i]);puts("");
    printf("%d",ans2.size()); for( int i = 0 ; i < ans2.size() ; ++i ) printf(" %d",ans2[i]);puts("");
}

int main() {
    while( ~scanf("%d",&n) ) {
        idx.clear(); a.clear(); 
        for( int i = 1 ; i <= n ; ++i ) {
            scanf("%d%d",&e[i].x,&e[i].y);
            e[i].id = i ;
            a.push_back( e[i].y );
        }
        sort( a.begin() , a.end() ) ;
        int tot = 2 ;
        for( int i = 0 ; i < a.size() ; ++i ) {
            if( idx.find( a[i] ) == idx.end() ) {
                idx[ a[i] ] = tot++ ;
            }
        }
        Gao(); Output();
    }
    return 0 ;    
}
View Code

 

posted @ 2015-05-22 09:34  hl_mark  阅读(331)  评论(0编辑  收藏  举报