【康复训练】【主席树】【BZOJ】1112: [POI2008]砖块Klo

Description

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

题解

主席树。只要求出中位数、比中位数小的数的总和和个数、比中位数大的数的总和和个数。

代码

#include
#include
#include
#define maxn 100006
#define maxs 2000006
#define LL long long
using namespace std;
inline char nc(){
    static char buf[100000],*i=buf,*j=buf;
    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
int n,m,K,a[maxn],b[maxn];
LL ans,Ln,Ls,Rn,Rs;
struct node{
    node *l,*r;
    int L,R,s;
    LL num;
    node(int x=0,int y=0){L=x;R=y;s=0;num=0;}
}nil,base[maxs];
typedef node* p_node;
p_node null=&nil,len=base,rot[maxn];
p_node newnode(int l,int r){
    *len=node(l,r);len->l=len->r=null;
    return len++;
}
p_node build(int l,int r){
    p_node x=newnode(l,r);
    if(l>=r)return x;
    int mid=l+r>>1;
    x->l=build(l,mid);x->r=build(mid+1,r);
    return x;
}
p_node update(p_node lst,int k){
    p_node x=newnode(lst->L,lst->R);
    x->l=lst->l;x->r=lst->r;x->s=lst->s;x->num=lst->num;
    if(x->L==x->R){x->s++;x->num+=b[k];return x;}
    int mid=x->L+x->R>>1;
    if(k<=mid)x->l=update(x->l,k);
         else x->r=update(x->r,k);
    x->s=x->l->s+x->r->s;x->num=x->l->num+x->r->num;
    return x;
}
int query(p_node lst1,p_node lst2,int k){
    if(lst1->L==lst1->R)return b[lst1->L];
    int tem=lst2->l->s-lst1->l->s;
    if(k<=tem)return Ln-=lst2->r->s-lst1->r->s,Ls-=lst2->r->num-lst1->r->num,query(lst1->l,lst2->l,k);
         else return Rn-=lst2->l->s-lst1->l->s,Rs-=lst2->l->num-lst1->l->num,query(lst1->r,lst2->r,k-tem);
}
int main(){
    null->l=null->r=null;
    freopen("klo.in","r",stdin);
    freopen("klo.out","w",stdout);
    n=_read();K=_read();
    for(int i=1;i<=n;i++)b[i]=a[i]=_read();
    sort(b+1,b+1+n);
    m=unique(b+1,b+1+n)-b-1;
    rot[0]=build(1,m);
    for(int i=1;i<=n;i++)rot[i]=update(rot[i-1],lower_bound(b+1,b+1+m,a[i])-b);
    ans=1e18;
    for(int r=K;r<=n;r++){
        int l=r-K;
        Ln=Rn=rot[r]->s-rot[l]->s;Ls=Rs=rot[r]->num-rot[l]->num;
        int mid=query(rot[l],rot[r],(K+1)>>1);
        ans=min(ans,Rs-Ls+(Ln-Rn)*mid);
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(BZOJ,主席树)