Bzoj1112--Poi2008砖块Klo

要使一个连续区间内的高度相同改变量最小,想想其实就是直线上很多点,选一个到所有点距离和最小的位置这种

平衡树维护一发中位数即可

对于花费是可以由上一个区间的花费计算过来的

只用比较一下前一次中位数和这一次中位数谁大,然后各自加加减减。例如2 3 3 5 2 4 ,找长度为3的区间,假设我们找到了3 5 2的花费为3,中位数为3,要求5 2 4的花费就是先减去3的花费0,加上4的花费1,得到5 2 4全部变到3的花费为4,然后因为这一次的中位数是4,所以把大于等于4的数花费减1,小于等于3的数花费加1,得到花费为3。

为了方便用了游程编码

代码:

#include<bits/stdc++.h>
#define MAXN 100005
#define MAXM 3005
#define INF 10000000000000LL
#define MOD 10000007
#define LL long long
#define int long long
using namespace std;

inline int read() {
    int ret=0,f=1;char c=getchar();
    while(c>'9'||c<'0') {if(c=='-') f=-1; c=getchar();}
    while(c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();}
    return ret*f;
}

int n,k,a[MAXN];

struct node{
    int son[2],s,par,sz;LL v,r;
}x[MAXN];
struct Treap{
    int L,R,root,cnt;
    void init() {
        L=0;R=1;root=MAXN-5;cnt=0;
        x[MAXN-5].r=INF;x[MAXN-5].v=INF;
    }
    
    inline void rotate(int num,int p) {
        int pa=x[num].par,t=x[num].sz;
        x[x[pa].par].son[x[x[pa].par].son[L]==pa?L:R]=num;
        x[num].sz=x[pa].sz;x[pa].sz-=t-x[x[num].son[p]].sz;
        x[pa].son[p^1]=x[num].son[p];if(x[num].son[p]) {x[x[num].son[p]].par=pa;}
        x[num].son[p]=pa;x[num].par=x[pa].par;x[pa].par=num;
    }
    
    void Insert(int v) {
        x[++cnt].v=v;x[cnt].r=rand()%MOD+1;x[cnt].s=1;x[cnt].sz=1;
        int now=root,pre;
        while(true) {
            if(v==x[now].v) {x[now].s++;x[now].sz++;cnt--;return;}
            pre=v<x[now].v?L:R;x[now].sz++;
            if(!x[now].son[pre]) {x[now].son[pre]=cnt;x[cnt].par=now;break;}
            now=x[now].son[pre];
        }
        now=cnt;
        while(true) {
            if(x[x[now].par].son[L]==now) pre=R;else pre=L;
            if(x[now].r>x[x[now].par].r) rotate(now,pre);
            else break;
        }
    }
    inline void Updata(int num,int v) {
        num=x[num].par;
        while(num) x[num].sz+=v,num=x[num].par;
    }
    void Del(int v) {
        int now=root;
        while(true) {
            if(v==x[now].v) {
                if(x[now].s>1) {x[now].s--;x[now].sz--;Updata(now,-1);return;}
                break;
            }
            now=x[now].son[v<x[now].v?L:R];
        }
        while(x[now].son[L]|x[now].son[R])
            if(x[x[now].son[L]].r>x[x[now].son[R]].r) rotate(x[now].son[L],R);
            else rotate(x[now].son[R],L);
        Updata(now,-1);
        x[x[now].par].son[x[x[now].par].son[L]==now?L:R]=0;
    }
    int Qurey(int k) {
        int now=root;
        if(k>x[root].sz) return -1;
        while(true) {
            if(x[x[now].son[L]].sz>=k-x[now].s&&x[x[now].son[L]].sz<k) return x[now].v;
            if(x[x[now].son[L]].sz<k) {k-=x[now].s+x[x[now].son[L]].sz;now=x[now].son[R];}
            else now=x[now].son[L];
            
        }
    }
    int Count_Treap(int v,int num) {
        if(!num) return 0;
        if(x[num].v>v) return Count_Treap(v,x[num].son[L]);
        else return Count_Treap(v,x[num].son[R])+x[x[num].son[L]].sz+x[num].s;
    }
    int Count(int v) {return Count_Treap(v,root);}
};

    #undef int
int main() {
    #define int long long
    srand(233333);
    n=read();k=read();
    for(int i=1;i<=n;i++) a[i]=read();
    Treap p;p.init();
    for(int i=1;i<=k;i++) p.Insert(a[i]);
    LL cost=0,ans=0;
    LL t=p.Qurey(k+1>>1),lt,delta,deltat;
    for(int i=1;i<=k;i++) cost+=abs(a[i]-t);
    ans=cost;lt=t;
    for(int i=k+1;i<=n;i++) {
        p.Del(a[i-k]);p.Insert(a[i]);
        t=p.Qurey(k+1>>1);
        delta=p.Count(min(t,lt));deltat=abs(t-lt);
        cost-=abs(a[i-k]-lt)-abs(a[i]-lt);
        if(t>lt) cost+=delta*deltat-(k-delta)*deltat;
        else cost+=(k-delta)*deltat-delta*deltat;
        ans=min(ans,cost);lt=t;
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2016-09-29 07:58  ihopenot  阅读(324)  评论(0编辑  收藏  举报