zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Excel 2016 Power View选项卡不显示的问题
    Base64编码
    MAPI错误0x80040107
    命令行界面 (CLI)、终端 (Terminal)、Shell、TTY的区别
    C函数调用过程原理及函数栈帧分析
    SIFT(Scale-invariant feature transform) & HOG(histogram of oriented gradients)
    Jupyter NoteBook 的快捷键
    endnote插入参考文献后的对齐方式和缩进空格
    赏月斋源码共享计划 第四期 约瑟夫问题
    LRU和LFU的区别
  • 原文地址:https://www.cnblogs.com/hlmark/p/4521496.html
Copyright © 2011-2022 走看看