Loading

最长上升子序列

还算比较模板的一道题了。

他让求每次的最长上升子序列,根据题意可以获得一个重要的信息。
就是现在放的数不会对之前的答案有影响。
因为之前的数都比他小,不肯能把它当作自己答案的一部分。

第二个信息,就是插入的时候序列中所有数都比他小。
所以我们只需要在之前的数里面找一个最大就行了。

得到如下算法

  1. 在平衡树中按坐标排序,同时另外开两个值域,一个存这个位置的值,一个存他子数中的最大值。
  2. 每当插入一个点的时候,把所有坐标比他小的点旋转成一个区间,然后取最大值。
  3. 刚刚的最大值+1得到这个数结尾的最长上升子序列,并插入平衡树。
  4. 全局最大之和刚刚的答案取\(max\)更新\(ans\),输出\(ans\)
  • 这里注意一下,自身答案和子数最值一定要开两个域,否则在更新的时候最大值可能把自身覆盖,得到错误答案。
  • 和火星人一样,硬插进去是平衡树的常用技巧
  • 任何修改操作都要\(splay\)到跟或者\(zt\)一下维护平衡树的平衡
code


#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <assert.h>
#define mp make_pair
#define R int
#define int long 
#define scanf Ruusupuu = scanf
#define printf Ruusupuu = printf

int Ruusupuu ;

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
typedef pair< int , int > PI ;
const int N = 1e5 + 10 ;
const int Inf = 1e9 ;

inline int read(){	
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ '0' ) , ch = getchar() ;
	return fg ? -w : w ; 
}

int n , pos , maxn ; 
int root , znt , fa [N] , ch [N][2] , val [N] , son [N] , sz [N] , mx [N] , pvl [N] ;

#define sk( x ) ( x == ch [fa [x]][1] )
#define tr( x , dlt ) ch [x][dlt > val [x]]

inline void zt( int x ){
	son [x] = ( son [ch [x][0]] + son [ch [x][1]] + sz [x] ) ;
	mx [x] = max( pvl [x] , max( mx [ch [x][0]] , mx [ch [x][1]] ) ) ; 
}

inline void spinup( int x ){
	R y = fa [x] , z = fa [y] , k = sk( x ) ;
	ch [z][sk(y)] = x , fa [x] = z ;
	ch [y][k] = ch [x][k ^ 1] , fa [ch [x][k ^ 1]] = y ;	
	ch [x][k ^ 1] = y , fa [y] = x ; 
	zt( y ) , zt( x ) ;
}

inline void splay( int x , int apos ){
	while( fa [x] != apos ){
		R y = fa [x] , z = fa [y] ;
		if( z != apos ) sk( x ) ^ sk( y ) ? spinup( x ) : spinup( y ) ; 
		spinup( x ) ;
	} if( !apos ) root = x ;
}

inline void ins( int dlt ){
	R now = root , fh = 0 ; 
	while( now && val [now] != dlt ) fh = now , now = tr( now , dlt ) ;
	if( now ) sz [now] ++ ;
	else {
		now = ++ znt ; 
		fa [now] = fh , val [now] = dlt ;
	 	son [now] = sz [now] = 1 ;
	 	if( fh ) tr( fh , dlt ) = now ; 
	} splay( now , 0 ) ;
}

inline int rk( int rank ){
	R now = root ;
	if( son [now] < rank ) return 0 ;
	while( 1 ){
		int nxt = ch [now][0] ;
		if( son [nxt] + sz [now] < rank ) rank -= ( son [nxt] + sz [now] ) , now = ch [now][1] ;
		else if( son [nxt] >= rank ) now = nxt ;
		else { splay( now , 0 ) ; return now ; }
	}
}

inline void chk( int dlt ){
	int l = rk( 1 ) , r = rk( dlt + 2 ) ;
	splay( l , 0 ) , splay( r , l ) ;
	int ans = mx [ch [ch [root][1]][0]] + 1 ;
	maxn = max( maxn , ans ) ;
	printf( "%ld\n" , maxn ) ; 
	
	l = rk( dlt + 1 ) , splay( l , 0 ) , splay( r , l ) ;
	ch [ch [root][1]][0] = ++ znt ;
	fa [znt] = ch [root][1] ;
	sz [znt] = son [znt] = 1 , pvl [znt] = ans ;
	splay( znt , 0 ) ;
}

void sc(){
	n = read() , ins( -Inf ) , ins( Inf ) ; 
}

void work(){
	while( n -- ) pos = read() , chk( pos ) ;
}

signed main(){	
	sc() ;
	work() ;
	return 0 ;
} 
posted @ 2021-07-11 06:06  Soresen  阅读(40)  评论(0)    收藏  举报