Review-堆(Bzoj1150)

1150: [CTSC2007]数据备份Backup

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 758   Solved: 317
[ Submit][ Status]

Description

 

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。


题解: 

首先要推出相邻的是最短的,但是相邻有种情况如样例:当你选取四个点中间两个点时,这两个点的距离加上两边的点之间的距离大于左边两点之间的距离与右边两点的距离,所以处理问题在用堆取出最小值(中间两点)要将左边两点和右边两点的距离和加入堆中,为了更好的表示取左边两个和右边两点时的情况,加入的是距离和减去中间两点的距离,这样加入后就将加入中间两点的距离消去。


代码:

program pro;
type heap=record pr,po:longint; end;
var
    he:array[-1..100]of heap;
    pos,ne,pre:array[-1..100050]of longint;
    lo:array[0..100050]of longint;
    ans,tot,n,m:longint;

procedure swap(var x,y:longint);
var
    k:longint;
begin
    k:=x; x:=y; y:=k;
end;

procedure pushup(x:longint);
begin
    while (he[x].pr<he[x shr 1].pr) do
    begin
        pos[he[x shr 1].po]:=x;
        swap(he[x].pr,he[x shr 1].pr);
        swap(he[x].po,he[x shr 1].po);
        x:=x shr 1;
    end;
    pos[he[x].po]:=x;
end;

procedure pushdown(x:longint);
var
    tmp:longint;
begin
    while (x shl 1<=tot) do
    begin
        tmp:=x shl 1;
        if (tmp<tot)and(he[tmp].pr>he[tmp+1].pr) then inc(tmp);
        if (he[x].pr>he[tmp].pr) then
        begin
            pos[he[tmp].po]:=x;
            swap(he[x].pr,he[tmp].pr);
            swap(he[x].po,he[tmp].po);
            x:=tmp;
        end
        else break;
    end;
    pos[he[x].po]:=x;
end;

procedure push(x,y:longint);
begin
    inc(tot);
    he[tot].pr:=x; he[tot].po:=y; pos[y]:=tot;
    pushup(tot);
end;

procedure delete(x:longint);
begin
    he[x].pr:=maxlongint;
    pushdown(x);
end;

procedure init;
var
    i:longint;
begin
    readln(n,m);
    for i:=1 to n do readln(lo[i]);
    for i:=2 to n do
    begin
        pre[i]:=i-1; ne[i]:=i+1;
        push(lo[i]-lo[i-1],i);
    end;
    pre[2]:=-1; ne[n]:=-1;
end;

procedure main;
var
    i,j,a,b:longint;
	k:heap;
begin
        init;
        for i:=1 to m do
        begin
			k.pr:=he[1].pr; k.po:=he[1].po;
		   if pre[k.po]=-1 then
           begin
                inc(ans,k.pr);
                delete(1); delete(pos[ne[k.po]]);
                pre[ne[ne[k.po]]]:=-1;
           end
           else
           if ne[k.po]=-1 then
           begin
                inc(ans,k.pr);
                delete(1); delete(pos[pre[k.po]]);
                ne[pre[pre[k.po]]]:=-1;
           end
           else
           begin
                inc(ans,k.pr);
                a:=ne[k.po]; b:=pre[k.po];
                pre[k.po]:=pre[b]; ne[pre[b]]:=k.po;
				ne[k.po]:=ne[a]; pre[ne[a]]:=k.po;
				he[1].pr:=he[pos[a]].pr+he[pos[b]].pr-he[1].pr;
                pushdown(1);
                delete(pos[a]); delete(pos[b]);
           end;
        end;
        writeln(ans);
end;

begin
    main;
end.




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值