码迷,mamicode.com
首页 > 其他好文 > 详细

种树 (堆模拟网络流)

时间:2018-09-01 22:09:45      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:break   个数   using   cond   数组   i++   描述   long   复制   

种树

题目描述

cyrcyr今天在种树,他在一条直线上挖了n个坑。这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树。而且由于cyrcyr的树种不够,他至多会种k棵树。假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利。

输入输出格式

输入格式:

第一行,两个正整数n,k。

第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利。

输出格式:

输出1个数,表示cyrcyr种树的最大获利。

输入输出样例

输入样例#1: 复制

6 3
100 1 -1 100 1 -1

输出样例#1: 复制

200

说明

对于20%的数据,n<=20。

对于50%的数据,n<=6000。

对于100%的数据,n<=500000,k<=n/2,在一个地方种树获利的绝对值在1000000以内。

题解

一道非常好的堆模拟网络流题。
首先我们来想想\(O(n^2)\)
很显然的两重循环dp
第一重枚举第i个位置,第二重枚举选了j颗树。
对于O(n)的模拟。
我们首先明确选了 i 就不能选 i-1 和 i+1。
所以所有的情况都是由选 i 和选 i-1 ,i+1 产生的。
选 i 时, i 的贡献应当是大于 i-1 和 i+1 的。
但是当我们发现选 i-1 和 i+1 要更好时呢?
网络流有一个操作就是反悔。
我们是不是也可以反悔一下呢?
因为先选了 i ,那么下一次选择的时候,如果反悔就是选两边
就是选了周围两个点,不反悔就是选其他点
那么把周围两个点维护为一个点就可以了。
\(vi[i]=vi[l[i]]+vi[r[i]]-vi[i]\)
然后维护一下 \(l\)\(r\) 数组。

代码

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
priority_queue<pair<int,int> >q;
int vis[1000001],ch[1000001],n,m;
long long ans;
struct node{
    int vi,id,l,r;
}t[1000001];
int read(){
    int x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}

int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++){
        ch[i]=t[i].vi=read();t[i].id=i;
        t[i].l=i-1;t[i].r=i+1;
        q.push(make_pair(ch[i],i));
    }
    t[0].r=1;t[n+1].l=n;
    while(m&&!q.empty()){
        while(vis[q.top().second])q.pop();
        int x=q.top().second;q.pop();
        if(t[x].vi<0)break;
        ans+=t[x].vi;
        t[x].vi=t[t[x].l].vi+t[t[x].r].vi-t[x].vi;
        vis[t[x].l]=vis[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(make_pair(t[x].vi,x));
        m--;
    }
    printf("%lld",ans);
    return 0;
}

种树 (堆模拟网络流)

标签:break   个数   using   cond   数组   i++   描述   long   复制   

原文地址:https://www.cnblogs.com/hhh1109/p/9571549.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!