zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    输入年月日,输出这一天是这一年的多少天
    判断体重是否标准 男标准=身高-100±3 女标准=身高-110±3
    if 条件运算符
    24小时换算成12小时&&判断正负数
    运算符(编程)
    定义变量
    基础知识
    java线程阻塞中断与LockSupport使用介绍(转)
    01背包问题--动态规划解法(2)(转载)
    01背包问题--动态规划解法
  • 原文地址:https://www.cnblogs.com/henry-1202/p/10092541.html
Copyright © 2011-2022 走看看