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;
}
posted @ 2025-09-08 18:38  FormulaOne  阅读(8)  评论(0)    收藏  举报