【bzoj1367】[Baltic2004]sequence 可并堆
题目描述
输入
输出
一个整数R
样例输入
7
9
4
8
20
14
15
18
样例输出
13
题解
可并堆,黄源河《左偏树的特点及其应用》Page 13例题原题
#include <cstdio> #include <cstring> #include <algorithm> #define N 1000010 using namespace std; int a[N] , root[N] , l[N] , r[N] , d[N] , w[N] , tot , si[N] , lp[N] , rp[N]; int merge(int x , int y) { if(!x) return y; if(!y) return x; if(w[x] < w[y]) swap(x , y); si[x] += si[y]; r[x] = merge(r[x] , y); if(d[l[x]] < d[r[x]]) swap(l[x] , r[x]); d[x] = d[r[x]] + 1; return x; } int main() { int n , i , j , p = 0; long long ans = 0; scanf("%d" , &n); for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]) , a[i] -= i; for(i = 1 ; i <= n ; i ++ ) { root[++p] = ++tot , w[tot] = a[i] , si[tot] = 1 , lp[p] = rp[p] = i; while(p > 1 && w[root[p]] < w[root[p - 1]]) { p -- , root[p] = merge(root[p] , root[p + 1]) , rp[p] = rp[p + 1]; while(2 * si[root[p]] > rp[p] - lp[p] + 2) root[p] = merge(l[root[p]] , r[root[p]]); } } for(i = 1 ; i <= p ; i ++ ) for(j = lp[i] ; j <= rp[i] ; j ++ ) ans += (long long)abs(w[root[i]] - a[j]); printf("%lld\n" , ans); return 0; }