【题解】洛谷P1484 种树(堆)

不难想到这道题需要处理权值最大值,而为了节省时间我们可以用大根堆来解决。

贪心的方法是把堆顶元素移除,并标记它与其相邻两个元素不可用,然后在那个位置添加上权值为左边+右边-堆顶值的元素,这样假如我们再找大根堆找到那个新加上的元素,就等效于我们选了第一次那个坑的左右两个坑。

具体实现的话我们开结构体,在堆里存下坑的序号与权值。并开数组记录某个坑的权值、某个坑左边那个坑的序号、某个坑右边那个坑的序号(这个我没开结构体,怕把自己搞晕)。读入所有坑的权值,并将其与序号放到堆里,记录其左边的坑的序号与右边坑的序号。记录新增序号tot初始化为n。当没挖够k个坑时,如果挖到当前堆顶是负数了,那就直接退出循环,如果堆顶不为空并且那个地方不可用,就把堆顶元素扔掉。(b数组记录不可用元素)。然后我们把堆顶元素拿出来,答案加上权值,扔掉,并标记当前序号与其左右序号均不可用。为了实现第二段所说的后半部分的操作,我们将tot++,记录权值,并更新最新的序号的左边那个序号为曾经的堆顶序号左边序号的左边序号,最新序号左边那个序号的右边那个序号为最新的序号;更新最新序号右边也是类似的操作。最后输出sum值即可

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const int maxn=500010;
int n,k;
struct node
{
	ll w;
	int num;
}a[maxn];
bool b[maxn];
ll c[maxn],sum=0;
int lft[maxn],rht[maxn];
priority_queue<node> q;
bool operator < (const node &o1,const node &o2)
{
	return o1.w<o2.w;
}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&c[i]);
		q.push((node){c[i],i});
		lft[i]=i-1;
		rht[i]=i+1;
	}
	int tot=n;
	while(k!=0)
	{
		while(!q.empty()&&b[q.top().num]==true)
		{
			q.pop();
		}
		if(q.empty()||q.top().w<0) break;
		node tmp=q.top();
		q.pop();
		sum+=tmp.w;
		b[tmp.num]=b[lft[tmp.num]]=b[rht[tmp.num]]=true;
		c[++tot]=c[lft[tmp.num]]+c[rht[tmp.num]]-c[tmp.num];
		lft[tot]=lft[lft[tmp.num]],rht[tot]=rht[rht[tmp.num]];
		rht[lft[tot]]=tot,lft[rht[tot]]=tot;
		q.push((node){c[tot],tot});
		k--;
	}
	printf("%lld",sum);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rem_Inory/article/details/81503603