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; }