博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ1112[POI2008]砖块Klo——非旋转treap
阅读量:6466 次
发布时间:2019-06-23

本文共 2372 字,大约阅读时间需要 7 分钟。

题目描述

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

输入

第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000

输出

最小的动作次数

样例输入

5 3
3
9
2
3
1

样例输出

2
 
考虑对于只有$k$个数的序列的最优解,显然是将所有数都变成中位数(因为如果变成的数比中位数小或者大都会有多于一半的数要改变)。
那么我们只需要维护出有$k$个连续数的序列,求出中位数并维护比中位数大的数的和及比中位数小的数的和即可得到这$k$个数的最优解,用平衡树维护即可。
对于$n$个数的序列只需要每次对连续$k$个数维护信息并求最优解然后取最小值即可。每次将第$i$个数删除,再将第$i+k$个数插入。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long longusing namespace std;ll ans;int n,k;int s[100010];struct treap{ treap *ls,*rs; int size; int val; int rnd; ll sum; treap(){} treap(treap *son,int v) { ls=rs=son; size=1; val=v; sum=1ll*v; rnd=rand(); } void pushup() { sum=ls->sum+rs->sum+val; size=ls->size+rs->size+1; }}tr[100010],nil;typedef treap* node;node root,null,cnt;node a,b,c;inline void init(){ nil=treap(NULL,0); null=&nil; null->ls=null->rs=null; null->size=0; root=null; cnt=tr;}inline node build(int v){ *cnt=treap(null,v); return cnt++;}inline node merge(node x,node y){ if(x==null) { return y; } if(y==null) { return x; } if(x->rnd
rnd) { x->rs=merge(x->rs,y); x->pushup(); return x; } else { y->ls=merge(x,y->ls); y->pushup(); return y; }}inline void split1(node rt,node &x,node &y,int k){ if(rt==null) { x=y=null; return ; } if(rt->ls->size>=k) { y=rt; split1(rt->ls,x,y->ls,k); } else { x=rt; split1(rt->rs,x->rs,y,k-1-rt->ls->size); } rt->pushup();}inline void split2(node rt,node &x,node &y,int k){ if(rt==null) { x=y=null; return ; } if(rt->val>=k) { y=rt; split2(rt->ls,x,y->ls,k); } else { x=rt; split2(rt->rs,x->rs,y,k); } rt->pushup();}inline void query(){ split1(root,a,b,k/2); split1(b,b,c,1); ll res=1ll*a->size*b->val-a->sum; res+=c->sum-1ll*c->size*b->val; ans=min(res,ans); root=merge(merge(a,b),c);}int main(){ srand(12378); scanf("%d%d",&n,&k); ans=1ll<<60; init(); for(int i=1;i<=n;i++) { scanf("%d",&s[i]); } for(int i=1;i<=k;i++) { split2(root,a,b,s[i]); root=merge(merge(a,build(s[i])),b); } query(); for(int i=k+1;i<=n;i++) { split2(root,a,b,s[i-k]); split1(b,b,c,1); root=merge(a,c); split2(root,a,b,s[i]); root=merge(merge(a,build(s[i])),b); query(); } printf("%lld",ans);}

转载于:https://www.cnblogs.com/Khada-Jhin/p/10731075.html

你可能感兴趣的文章
第三十九天
查看>>
Redis详解
查看>>
论程序员加班的害处
查看>>
codeblocks快捷键
查看>>
基于HTML5的WebGL设计汉诺塔3D游戏
查看>>
WPF资料链接
查看>>
过滤DataTable表中的重复数据
查看>>
再次更新
查看>>
mysql的数据类型int、bigint、smallint 和 tinyint取值范围
查看>>
移动铁通宽带上网设置教程
查看>>
Python算法(含源代码下载)
查看>>
利用Windows自带的Certutil查看文件MD5
查看>>
通过原生js添加div和css
查看>>
简单的导出表格和将表格下载到桌面上。
查看>>
《ArcGIS Engine+C#实例开发教程》第一讲桌面GIS应用程序框架的建立
查看>>
查询指定名称的文件
查看>>
AJAX POST&跨域 解决方案 - CORS
查看>>
开篇,博客的申请理由
查看>>
Servlet 技术全总结 (已完成,不定期增加内容)
查看>>
[JSOI2008]星球大战starwar BZOJ1015
查看>>