BZOJ1112: [POI2008]砖块Klo

Description

N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.

Input

第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000

Output

最小的动作次数

Sample Input

5 3
3
9
2
3
1

Sample Output

2

HINT

原题还要求输出结束状态时,每柱砖的高度.本题略去.

Solution

问题可以这么描述为,求一个数x和一个区间[l...r],使sum_{i=l}^{r}{x-a_i}最小。

容易想到的是这个x就是区间[l...r]的中位数。

那么现在就需要一个数据结构快速维护带插入删除的中位数,使用fhq-treap即可。

然后我的板子奇奇怪怪的需要一个虚点来当根所以中位数是k>>1+2...

注意要开longlong,以及,如果偷懒使用define int longlong的时候一定要在代码的最上方,至少要在读优的上方!!!!!!!!!!!!!!!!!

#include <bits/stdc++.h>

#define ll long long
#define inf 0x7ffffffff
#define il inline
#define debug puts("233")
#define int long long

namespace io {

    #define in(a) a=read()
    #define out(a) write(a)
    #define outn(a) out(a),putchar('
')

    #define I_int int
    inline I_int read() {
        I_int x = 0 , f = 1 ; char c = getchar() ;
        while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; }
        while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; }
        return x * f ;
    }
    char F[ 200 ] ;
    inline void write( I_int x ) {
        if( x == 0 ) { putchar( '0' ) ; return ; }
        I_int tmp = x > 0 ? x : -x ;
        if( x < 0 ) putchar( '-' ) ;
        int cnt = 0 ;
        while( tmp > 0 ) {
            F[ cnt ++ ] = tmp % 10 + '0' ;
            tmp /= 10 ;
        }
        while( cnt > 0 ) putchar( F[ -- cnt ] ) ;
    }
    #undef I_int

}
using namespace io ;

using namespace std ;

#define N 100010

int n , k , root = 1 ,tot = 0;
struct fhq {
    int siz , val , rnk , lc , rc , sum ;
}t[N];

void up(int rt) { 
    t[rt].siz = t[t[rt].lc].siz + t[t[rt].rc].siz + 1;
    t[rt].sum = t[t[rt].lc].sum + t[t[rt].rc].sum + t[rt].val; 
}

void split(int &a , int &b , int val , int rt) {
    if(!rt) {
        a = b = 0;
        return;
    }
    if(t[rt].val <= val) a = rt , split(t[a].rc , b , val , t[rt].rc) ;
    else b = rt , split(a , t[b].lc , val , t[rt].lc) ;
    up(rt);
}

void merge(int a , int b , int &rt) {
    if(!a || !b) {
        rt = a + b;
        return;
    }
    if(t[a].rnk < t[b].rnk) rt = a , merge(t[a].rc , b , t[rt].rc) ;
    else rt = b , merge(a , t[b].lc , t[rt].lc) ;
    up(rt);
}

int new_node(int val) {
    t[++tot] = (fhq) {1 , val , rand() , 0 , 0 , val} ;
    return tot ;
}

void insert(int val) {
    int x = 0 , y = 0 , z = new_node(val) ;
    split(x , y , val - 1, root) ;
    merge(x , z , x) ; merge(x , y , root) ;
}

void erase(int val) {
    int x = 0 , y = 0 , z = 0;
    split(x , y , val , root); split(x , z , val - 1 , x);
    merge(t[z].lc , t[z].rc , z) ; merge(x , z , x) ; merge(x , y , root) ;
}

int find_kth(int rnk , int rt) {
    while(1) {
        if(t[t[rt].lc].siz + 1 < rnk) rnk -= t[t[rt].lc].siz + 1, rt = t[rt].rc;
        else if(t[t[rt].lc].siz >= rnk) rt = t[rt].lc ;
        else return t[rt].val; 
    }
}

void print(int rt) {
    if(t[rt].lc) print(t[rt].lc) ;
    cout<<t[rt].val<<" ";
    if(t[rt].rc) print(t[rt].rc) ;
}

int query(int val) {
    int x = 0 , y = 0 , z = 0 ;
    split(x , y , val , root) ;
    split(x , z , val - 1 , x) ;
    int s1 = 1ll * (t[x].siz - 1)* val , s2 = 1ll * t[y].siz * val ;
    int a1 = t[x].sum , a2 = t[y].sum ;
//    cout<<a1<<" "<<a2<<" "<<endl;
    merge(x , z , x) ; merge(x , y , root) ;
//    cout<<s1-a1+a2-s2<<endl;
    return s1 - a1 - s2 + a2 ;
}

int a[N] ;

signed main() {
/*    freopen("1112.in","r",stdin);
    freopen("1112.out","w",stdout);*/
    srand((unsigned)time(0)) ;
    n = read() , k = read() ;
    new_node(0) ; t[1].siz = 0 ;
    for(int i = 1 ; i <= n ; i ++) a[i] = read() ;
    ll ans = 2e18 , M = 0 , L = 0 , R = 0; a[0] = 0;
    for(int i = 0 ; i < k ; i ++) insert(a[i]) ;
    int l = 0 , r = k - 1 ;
    while(r < n) {
        ++l , ++r ;
        erase(a[l - 1]) ; insert(a[r]) ;
        int mid = find_kth((k>>1)+2 , root) ;
        ll tmp = query(mid) ;
        if(tmp < ans) {
            M = mid ; L = l ; R = r;
            ans = tmp;
        }
//        print(root);puts("");
//        cout<<l<< " "<<r<<" "<<mid<<endl;
    }
    outn(ans); 
/*    for(int i = 1 ; i < L ; i ++) outn(a[i]) ;
    for(int i = L ; i <= R; i ++) outn(M) ;
    for(int i = R + 1 ; i <= n; i ++) outn(a[i]) ;*/
    return 0;
}
原文地址:https://www.cnblogs.com/henry-1202/p/10092541.html