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;
} 
Ac

 

posted @ 2020-07-21 18:23  Simex  阅读(147)  评论(0编辑  收藏  举报