首页 > 代码库 > bzoj2151: 种树(双向链表+堆)
bzoj2151: 种树(双向链表+堆)
题目大意:n个数围成一个圈,选了某个数就不能选它相邻的两个数,问选m个数,最大值为多少。
先用堆维护n个数的最大值,每次取出最大值加进答案,选了某个数之后有可能选它相邻的两个比他更优,所以把旁边的两个数删掉,把这次选的数的值改成左边的数+右边的数-这次选的数,如果下次取了这个数相当于不选这个数换成另外两个,选择m次就是取了m个数。一个数的左右两边的数就用双向链表来搞就行了。
代码如下:
var n,m,x,i,ans:longint; l,r,heap,pos,a:array[0..200001]of longint; procedure down(i:longint); var t,j:longint; begin while (i<<1<=n) do begin if (i<<1=n)or(a[heap[i<<1]]>a[heap[i<<1 or 1]]) then j:=i<<1 else j:=i<<1 or 1; if a[heap[i]]<a[heap[j]] then begin t:=heap[i];heap[i]:=heap[j];heap[j]:=t; t:=pos[heap[i]];pos[heap[i]]:=pos[heap[j]];pos[heap[j]]:=t; i:=j; end else exit; end; end; procedure up(i:longint); var t:longint; begin while i>1 do begin if a[heap[i]]>a[heap[i>>1]] then begin t:=heap[i];heap[i]:=heap[i>>1];heap[i>>1]:=t; t:=pos[heap[i]];pos[heap[i]]:=pos[heap[i>>1]];pos[heap[i>>1]]:=t; i:=i>>1; end else exit; end; end; begin readln(n,m); if (m>n>>1) then writeln(‘Error!‘) else begin for i:=1 to n do begin read(a[i]); l[i]:=i-1;r[i]:=i+1;heap[i]:=i;pos[i]:=i;up(i); end; l[1]:=n;r[n]:=1; for i:=1 to m do begin x:=heap[1];inc(ans,a[x]); a[x]:=a[l[x]]+a[r[x]]-a[x];down(pos[x]); a[l[x]]:=-maxlongint;down(pos[l[x]]);l[x]:=l[l[x]]; a[r[x]]:=-maxlongint;down(pos[r[x]]);r[x]:=r[r[x]]; l[r[x]]:=x;r[l[x]]:=x; end; writeln(ans); end; end.
PS:我才知道堆可以这么拿来删元素QAQ
bzoj2151: 种树(双向链表+堆)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。