bzoj 1150 [CTSC2007]数据备份Back…

Description

bzoj <wbr>1150 <wbr>[CTSC2007]数据备份Backup

Input

输入的第一行包含整数n和k,其中n(2 ≤ n ≤100 000)表示办公楼的数目,k(1≤ k≤ n/2)表示可利用的网络电缆的数目。接下来的n行每行仅包含一个整数(0≤ s ≤1000 000 000), 表示每个办公楼到大街起点处的距离。这些整数将按照从小到大的顺序依次出现。

Output

输出应由一个正整数组成,给出将2K个相异的办公楼连成k对所需的网络电缆的最小总长度。

Sample Input

5 2
1
3
4
6
12

Sample Output

4

HINT

上面的样例输入给出了前面描述的示例情形

对于每一个测试点,如果写到输出文件中的答案正确,则得到该测试点100%的分数,否则得零分。30%的输入数据满足n≤20。60%的输入数据满足n≤10 000。

 

贴个题解。

http://hi.baidu.com/cao_ximeng/blog/item/00f3d81c0c66071134fa415b.html

 

由于我的蒟蒻。。这道题的调试都用在调堆上了。。。一开始怎么也想不到是映射堆写跪了。。。

在对维护中,一个很重要的步骤被我给忽略了。。在删除堆顶的元素的时候,只要把最后一个元素swap上来再向下推。

但是!!!对于堆中元素的更新就必须考虑往上走的情况了!!

因为堆中的每个元素如果不是在最底层,会有相应的两个儿子,这两个儿子是没有直接关系的。对于堆有初步了解的人都知道堆顶元素的左子树可以全部小于(或大于)右子树。

那么在删除堆中的元素的时候,swap上来的最后一个元素有可能是仅比堆顶小一点的值。。。

那么就要先往上走了。。。

还有一点。如果删除的刚好就是最后一个元素。直接删之。。。我蒟蒻地没判断。。。让空单元到堆里面乱窜。。。

 

太讽刺了。。。竟然还要恶补堆的基本操作。。。我该是有多弱啊。。。

 

AC CODE

 

program bzoj_1150;
var heap,pi,l,r:array[0..101000] of longint;
    d:array[0..101000] of int64;
    n,k,tot:longint;
//======================================================
procedure swap(x,y:longint);
var tt:longint;
begin
  pi[heap[x]]:=y; pi[heap[y]]:=x;
  tt:=heap[x]; heap[x]:=heap[y]; heap[y]:=tt;
end;
//======================================================
procedure ins(x:longint);
begin
  inc(tot); heap[tot]:=x; pi[x]:=tot;
  x:=tot;
  while x>1 do
    if d[heap[x]]<d[heap[x shr 1]] then
    begin
      swap(x,x shr 1);
      x:=x shr 1;
    end else break;
end;
//======================================================
procedure del(x:longint);
var g,h,i:longint;
begin
  swap(x,tot);
  pi[heap[tot]]:=0; heap[tot]:=0;
  dec(tot);
  if x>tot then exit;
  while x>1 do
    if d[heap[x]]<d[heap[x shr 1]] then
    begin
      swap(x,x shr 1);
      x:=x shr 1;
    end else break;
  i:=x;
  while i<tot do
  begin
    g:=i shl 1; h:=i shl 1+1;
    if (g<=tot) and (d[heap[g]]<d[heap[i]]) then
    begin
      if (h<=tot) and (d[heap[h]]<d[heap[g]]) then
      begin
        swap(i,h);
        i:=h;
      end else
      begin
        swap(i,g);
        i:=g;
      end;
    end else
    if (h<=tot) and (d[heap[h]]<d[heap[i]]) then
    begin
      swap(i,h);
      i:=h;
    end else break;
  end;
end;
//======================================================
procedure init;
var i:longint;
    pre,now:int64;
begin
  readln(n,k); readln(pre);
  for i:=2 to n do
  begin
    readln(now); d[i]:=now-pre;
    l[i]:=i-1; r[i]:=i+1;
    ins(i); pre:=now;
  end;
  d[1]:=maxlongint; d[n+1]:=maxlongint;
  r[1]:=1; l[n+1]:=n; r[0]:=1; l[n+2]:=n+1;
  ins(1); ins(n+1);
end;
//======================================================
procedure main;
var now,i,tmp:longint;
    ans:int64;
begin
  ans:=0;
  for i:=1 to k-1 do
  begin
    ans:=ans+d[heap[1]];
    now:=heap[1]; del(1);
    del(pi[l[now]]); del(pi[r[now]]);
    d[now]:=d[r[now]]+d[l[now]]-d[now];
    r[l[l[now]]]:=now; l[r[r[now]]]:=now;
    l[now]:=l[l[now]]; r[now]:=r[r[now]];
    ins(now);
  end; ans:=ans+d[heap[1]]; writeln(ans);
end;
//======================================================
begin
  assign(input,'1.in'); reset(input);
  init;
  main;
end.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值