P1484 种树
链接:Miku
--------------------------------
链表存图,但是要注意创造出来个0和n+1号坑,这会方便我们后续处理的
--------------------------------
贪心的部分就是选择最高的,然后把两边的去掉
等等,我反悔了咋办,我觉得选两边的更好!(这里有一个问题,要不都选,要不都不选,这是可以证明的)
那么我们就把两边和中间拼成一颗巨树,他的价值是两边之和-中间的(这样再选它,就正好是抵消中间并且变成了两边的和)
然后优先队列弹弹弹。
注意:这里有负的,所有要特判。
----------------------------------
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> using namespace std; int n,k; int l[500002],r[500002],num[500002];long long v[500002]; struct tr{ int l; int r; int num; long long va; friend bool operator < (tr a,tr b){ return a.va<b.va; } } t[500001],tt; long long ans; long long x; priority_queue <tr>q; int fl[500001]; int main(){ scanf("%lld%lld",&n,&k); for(int i=1;i<=n;++i){ scanf("%lld",&x); t[i].va=x; t[i].l=i-1;f t[i].r=i+1; t[i].num=i; q.push(t[i]); } t[0].r=1;//省事之极 t[n+1].l=n; for(int i=1;i<=k;++i){ while(!q.empty()&&(fl[q.top().num]))//不能选的踢出去 q.pop(); tt=q.top();q.pop(); if(tt.va<0) { break; } ans+=tt.va; x=tt.num; t[x].va=t[t[x].l].va+t[t[x].r].va-t[x].va;//额外开一个数组很有必要,不然找不到左右 tt.va=t[x].va; fl[t[x].l]=fl[t[x].r]=1;//两边踢出去 t[x].l=t[t[x].l].l;t[t[x].l].r=x;//把左右合并成巨坑 t[x].r=t[t[x].r].r;t[t[x].r].l=x; q.push(tt); } cout<<ans; return 0; }