SP1553题解
题面
本题不算太难,方法与 [国家集训队]种树 类似,我们通过双向链表维护数列,优先队列求最值。
我们设
当我们从优先队列中取出一个值时,把它累加进答案后,就表示我们选了这棵树。那么它两边的树就都不能选了。但是,有可能选两边会更优。
这时,代码的精髓就来了:“后悔处理”。如果现在我们选了
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,m,ans,a[100005];
int l[100005],nxt[100005],per[100005];//链表
struct node{
int a,x;
node(){}
node(int c,int d){a=c,x=d;}
bool operator<(const node &t)const{//重载运算符
return a>t.a;
}
};
priority_queue<node>q;
bool vis[100005];//判断一个元素有没有被删除
signed main()
{
scanf("%d",&t);
while(t--){
ans=0;
memset(vis,0,sizeof(vis));
while(!q.empty())q.pop();//清空
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<n;i++)q.push(node(a[i+1]-a[i],i));
for(int i=1;i<n;i++)nxt[i]=i+1,per[i]=i-1,l[i]=a[i+1]-a[i];n--;//初始化链表、优先队列
l[0]=l[n+1]=INT_MAX;//将两边设为极大值,防止影响答案
while(m--){
while(vis[q.top().x])q.pop();
node tmp=q.top();
q.pop();
vis[nxt[tmp.x]]=vis[per[tmp.x]]=1;//标记(就是这个)
ans+=tmp.a;//累加答案
tmp.a=-tmp.a+l[nxt[tmp.x]]+l[per[tmp.x]];//修改tmp.a的值为-tmp.a+l[nxt[tmp.x]]+l[per[tmp.x]](后悔处理)
l[tmp.x]=tmp.a;
per[nxt[nxt[tmp.x]]]=tmp.x;
nxt[tmp.x]=nxt[nxt[tmp.x]];
nxt[per[per[tmp.x]]]=tmp.x;
per[tmp.x]=per[per[tmp.x]];//删除两边的元素
q.push(tmp);
}
printf("%lld\n",ans);
}
return 0;
}
md,写题解的时候为了美观调换了几行的位置,结果挂了,警钟长鸣。