已知A求单增B使得∑|Ai-Bi|最小(左倾堆实现)

1.左倾堆的节点的键值小于等于子节点的键值(堆性质)
2.左孩子的NPL大于等于右孩子的NPL(左倾性质)
3.NPLF=NPLRC+1
4.左倾堆的子树为左倾堆
#include
#include
#include
#include
using namespace std;
const int N=50005;
int a[N],root[N],num[N];
struct LHeap{
int l,r,key,dis,sz;
bool operator<(const LHeap lh)const{
return key<lh.key;
}
}tr[N];
int cnt_tr;
int NewTree(int k){
tr[++cnt_tr].key=k;
tr[cnt].l=tr[cnt].r=tr[cnt].dis=0;
tr[cnt].sz=1;
return cnt_tr;
}
int Merge(int x,int y){
if(!x||!y)return x+y;
if(tr[x]<tr[y])swap(x,y);
tr[x].r=Merge(tr[x].r,y);
if(tr[tr[x].r].dis>tr[tr[x].l].dis)swap(tr[x].r,tr[x].l);
tr[x].dis=tr[tr[x].r].dis+1;
tr[x].sz=tr[tr[x].r].sz+tr[tr[x].l].sz+1;
return x;
}
int Top(int x){
return tr[x].key;
}
void Pop(int &x){
x=Merge(tr[x].l,tr[x].r);
}
int main(){
int n;
while(~scanf("%d",&n)&&n){
int sum=0,ans=0,cnt_root=0;
cnt_tr=0;
for(int i=1;i<=n;i++){
scanf("%d",a+i);
sum+=a[i];
}
for(int i=0;i<n;i++){
root[++cnt_root]=NewTree(a[i]);
num[cnt_root]=1;
while(cnt_root>1&&Top(root[cnt_root]<Top(root[cnt_root-1])){
cnt_root–;
roo[cnt_root]=Merge(root[cnt_root],root[cnt_root+1]);
num[cnt_root]+=num[cnt_root+];
while(tr[root[cnt_root]].sz*2>num[cnt_root]+1)Pop(root[cnt]);
}
}
int px=0;
for(int i=1;i<=cnt_root;i++)
for(int j=0,x=Top(root[i]);j<num[i];j++)
ans+=abs(a[px++]-x);
printf("%d",ans);
}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值