最长上升子序列
还算比较模板的一道题了。
他让求每次的最长上升子序列,根据题意可以获得一个重要的信息。
就是现在放的数不会对之前的答案有影响。
因为之前的数都比他小,不肯能把它当作自己答案的一部分。
第二个信息,就是插入的时候序列中所有数都比他小。
所以我们只需要在之前的数里面找一个最大就行了。
得到如下算法
- 在平衡树中按坐标排序,同时另外开两个值域,一个存这个位置的值,一个存他子数中的最大值。
- 每当插入一个点的时候,把所有坐标比他小的点旋转成一个区间,然后取最大值。
- 刚刚的最大值+1得到这个数结尾的最长上升子序列,并插入平衡树。
- 全局最大之和刚刚的答案取\(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 ;
}
$The \ light \ has \ betrayed \ me$

浙公网安备 33010602011771号