题解:P14030 【MX-X20-T4】「FAOI-R7」连接时光 I
简单
设
对于
对于
考虑
具体地,将
由于
考虑全负数。
贪心的想,我们只希望代价最小即
那么对于后缀最大值的点
此时代价为后缀最大值求和,显然没有更少代价。
结合起来,考虑找出最大的
序列被分为两部分,
对于后部分,全为负数,套用上面的做法。
前部分
然后将前部分看作一个整体,让后部分后缀最大值向前半部分连边即可。
此时我们可以得出
一个简洁做法是
::::success[Code]
#include <bits/stdc++.h>
//#define int long long
#define PII pair < int , int >
#define x first
#define y second
using namespace std ;
bool bbb ;
const int N = 2e5 + 5 , inf = 1e9 ;
int n , c[N] , mx[N] ;
int f[N] , a[N] ;
int tr[N] ;
#define lowbit(x) (x & -x)
void add(int x , int d){ while(x <= n) tr[x] += d , x += lowbit(x) ; }
int sum(int x){ int res = 0 ; while(x) res += tr[x] , x -= lowbit(x) ; return res ; }
void solve(){
cin >> n ;
for(int i = 1 ; i <= n ; i++) cin >> c[i] ;
int p = 0 ;
mx[n + 1] = -inf ;
for(int i = n ; i >= 1 ; i--){
mx[i] = max(mx[i + 1] , c[i]) ;
if(!p && mx[i] >= 0) p = i ;
}
for(int i = 1 ; i <= p ; i++)
f[i] = c[i] >= 0 ? i - 1 : 0 ;
int lat = p ? p : 1 ;
for(int i = p + 1 ; i <= n ; i++)
if(c[i] == mx[i]){
f[i] = i - lat ;
lat = i ;
}
long long ans = 0 ;
for(int i = 1 ; i <= n ; i++) ans += 1ll * f[i] * c[i] ;
cout << ans << '\n' ;
for(int i = 1 ; i <= n ; i++) add(i , 1) ;
for(int i = n ; i >= 1 ; i--){
int x = 0 , s = 0 , rk = i - f[i] ;
for(int j = __lg(n) ; ~j ; j--)
if(x + (1 << j) <= n && s + tr[x + (1 << j)] < rk)
x += 1 << j , s += tr[x] ;
++ x ;
a[i] = x , add(x , -1) ;
}
for(int i = 1 ; i <= n ; i++)
cout << a[i] << (i == n ? '\n' : ' ') ,
f[i] = a[i] = c[i] = 0 ;
}
bool eee ;
signed main(){
// freopen("light.in" , "r" , stdin) ;
// freopen("light.out" , "w" , stdout) ;
ios :: sync_with_stdio(0) ;
cin.tie(0) ; cout.tie(0) ;
cerr << "Memory: " << abs((char*)&eee - (char*)&bbb) / 1024.0 / 1024.0 << " MB\n" ;
int T ; cin >> T ;
while(T--) solve() ;
return 0 ;
}
/*
4
2 4 -2 0
6
7 1 -1 -7 1 -2
*/
::::
这里是
前部分就是上面的构造。
此时考察一个块