CF2031D
一眼 dp。
设 \(f_i\) 表示从第 \(i\) 个位置出发能跳到的最大值。考虑从后往前枚举,对于当前位置 \(i\),其往前跳到的最大值即为 \(a\) 的前缀最大值。而如果先往后跳,那么就可以跳到比 \(a_i\) 小的位置。而这些位置能跳到的最大值已经计算好了,因此可以直接使用。转移的位置只与 \(a_i\) 有关,因此只需要维护 \(f\) 的前缀最大值并支持单点修改即可。树状数组就是一种简单的方法。
单组数据时间复杂度 \(O(n \log n)\)。
#include <iostream>
#include <cstdio>
#define int long long
using namespace std;
int n,f[1000001],a[1000001],mx[1000001],mi[1000001],t[2000001],k,tot;
int lowbit( int x )
{
return x & ( -x );
}
void xg( int x , int y )
{
for( int i = x ; i <= n ; i += lowbit( i ) )
t[i] = max( t[i] , y );
return;
}
int cx( int x )
{
int s = 0;
for( int i = x ; i >= 1 ; i -= lowbit( i ) )
s = max( s , t[i] );
return s;
}
void solve( void )
{
cin >> n;
for( int i = 1 ; i <= n ; i ++ )
cin >> a[i];
for( int i = 1 ; i <= n * 2 ; i ++ )
t[i] = 0;
mx[1] = a[1];
for( int i = 2 ; i <= n ; i ++ )
mx[i] = max( mx[i - 1] , a[i] );
for( int i = n ; i >= 1 ; i -- )
{
f[i] = mx[i];
f[i] = max( f[i] , cx( mx[i] - 1 ) );
xg( a[i] , f[i] );
}
for( int i = 1 ; i <= n ; i ++ )
cout << f[i] << ' ';
cout << '\n';
return;
}
signed main()
{
ios::sync_with_stdio( false );
cin.tie( 0 );
cout.tie( 0 );
int T;
cin >> T;
while( T -- )
solve();
return 0;
}

浙公网安备 33010602011771号