题干:
N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务。
题意就是给你一个长为n的序列,找出长为k的一段,使得将其修改成 所有数字相同 的花费最小。
乍看以为是dp,但是仔细一看这不是treap吗?
(结果treap删除写崩了,t了5次。)
代码:
#include<ctime> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100050 typedef long long ll; inline int rd() { int f=1,c=0;char ch = getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n,k,tot,rt,a[N]; struct Treap { int ls,rs; int siz,w,vl,rnd; }tr[N]; void update(int u) { tr[u].siz = tr[tr[u].ls].siz+tr[tr[u].rs].siz+tr[u].w; } void lturn(int &x) { int y = tr[x].rs; tr[x].rs = tr[y].ls; tr[y].ls = x; tr[y].siz= tr[x].siz; update(x); x=y; } void rturn(int &x) { int y = tr[x].ls; tr[x].ls = tr[y].rs; tr[y].rs = x; tr[y].siz=tr[x].siz; update(x); x=y; } void insert(int &k,int x) { if(!k) { k=++tot; tr[k].siz = tr[k].w = 1; tr[k].vl = x; tr[k].rnd = rand(); return ; } tr[k].siz++; if(tr[k].vl==x) { tr[k].w++; }else if(x<tr[k].vl) { insert(tr[k].ls,x); if(tr[tr[k].ls].rnd<tr[k].rnd)rturn(k); }else { insert(tr[k].rs,x); if(tr[tr[k].rs].rnd<tr[k].rnd)lturn(k); } } void erase(int &k,int u) { if(!k)return ; if(tr[k].vl==u) { if(tr[k].w>1) { tr[k].w--; tr[k].siz--; }else { if(tr[k].ls*tr[k].rs==0)k = tr[k].ls+tr[k].rs; else if(tr[tr[k].ls].rnd<tr[tr[k].rs].rnd) { rturn(k); erase(k,u); }else { lturn(k); erase(k,u); } } }else if(u>tr[k].vl) { tr[k].siz--; erase(tr[k].rs,u); }else { tr[k].siz--; erase(tr[k].ls,u); } } int k1,k2,k3; int query_kth(int &u,int k) { int t = tr[tr[u].ls].siz; if(k<=t)return query_kth(tr[u].ls,k); else if(k<=t+tr[u].w){k1+=t;k2=tr[u].w;return tr[u].vl;} else {k1+=(t+tr[u].w);return query_kth(tr[u].rs,k-t-tr[u].w);} } int main() { srand(time(NULL)); n=rd(),k=rd(); ll ans = 233333333333333333ll,now=0; int las_mid,cnt=0; for(int i=1;i<=n;i++) { if(i<=k)cnt=i; k1=k2=0; a[i]=rd(); insert(rt,a[i]); if(i-k>0)erase(rt,a[i-k]); int mid = query_kth(rt,(cnt+1)>>1); k3 = cnt-k1-k2; if(i!=1) { now+=(ll)abs(las_mid-a[i]); if(i-k>0)now-=(ll)abs(las_mid-a[i-k]); if(mid<las_mid) { now-=(ll)(k1+k2-k3)*(las_mid-mid); }else if(mid>las_mid) { now-=(ll)(k2+k3-k1)*(mid-las_mid); } } if(i>=k)ans=ans<now?ans:now; las_mid = mid; } printf("%lld ",ans); return 0; }