题目描述
给定一个长度为 N 的整数数列:A1, A2, . . . , AN。你要重复以下操作 K 次:
每次选择数列中最小的整数(如果最小值不止一个,选择最靠前的),将其删除。并把与它相邻的整数加上被删除的数值。输出 K 次操作后的序列。
思路
首先,多次删除的操作让我们可以想到可以使用链表。然后,取最小值的操作可以联想到使用小根堆。
然后就剩下了一个难点:如何表示每次删除数时给相邻数加上对应值。
因为小根堆不能更新已经存入在堆中的数据。所以我们在堆中只需要存储数据的val值与下标pos就行。取数据时根据所取得数据下标找到对应数据。
由于val值可能会变化,所以堆顶得数据不一定是目前的最小值,我们可以在链表结点上先标记增加值。然后在每次取最大值结点时判断一下是否存在增加值,如果有标记值,更新一下结点值,然后把结点重新存放回小根堆中。
(注意点:int可能会溢出,记得开long long)
代码
#include<bits/stdc++.h>
using namespace std;
#define pii pair<long long,int>
struct node{
long long val;
long long add;
int l,r;
bool st;
}nod[500005];
int main(){
int n,k;
priority_queue<pii,vector<pii>,greater<pii> >heap;
cin>>n>>k;
for(int i=1;i<=n;i++){
long long v;cin>>v;
nod[i]={v,0,i-1,i+1,0};
heap.push({v,i});
}
while(k--){
int pos=heap.top().second;heap.pop();
while(nod[pos].add){
nod[pos].val+=nod[pos].add;
nod[pos].add=0;
heap.push({nod[pos].val,pos});
pos=heap.top().second;heap.pop();
}
int l=nod[pos].l;
int r=nod[pos].r;
nod[pos].st=1;
long long val=nod[pos].val;
nod[l].add+=val;
nod[r].add+=val;
nod[l].r=r;
nod[r].l=l;
}
for(int i=1;i<=n;i++){
if(!nod[i].st){
cout<<nod[i].val+nod[i].add<<' ';
}
}
}