题解:P10392 [蓝桥杯 2024 省 A] 封印宝石
P10392 [蓝桥杯 2024 省 A] 封印宝石
P10392 [蓝桥杯 2024 省 A] 封印宝石
思路
看到字典序,显然贪心。枚举放的当前位置,每次在体力允许的情况下,尽可能地放魔力值较大的物品到当前位置。那任意两个相邻盒子不能存放魔力值相同的宝石如何满足呢?如果当前区间最大值与上一个位置的值一样,那我们就换成严格次大值就可以了。
线段树维护区间最大值和次大值,同时为了计算体力消耗,还要维护最大值以及次大值的下标。
代码
给出一个很丑的区间次大值实现。
#include<bits/stdc++.h>
using namespace std;
struct Node{
int mxpos,mx = INT_MIN,smxpos,smx = INT_MIN;
Node operator+(const Node &x)const{
Node res;
if(mx >= x.mx){
res.mx = mx;
res.mxpos = mxpos;
}
else{
res.mx = x.mx;
res.mxpos = x.mxpos;
}
if(mx == x.mx){
if(smx >= x.smx){
res.smx = smx;
res.smxpos = smxpos;
}
else{
res.smx = x.smx;
res.smxpos = x.smxpos;
}
}
else{
if(mx > x.mx){
res.smx = max({x.mx,x.smx,smx});
if(res.smx == smx) res.smxpos = smxpos;
else if(res.smx == x.smx) res.smxpos = x.smxpos;
else if(res.smx == x.mx) res.smxpos = x.mxpos;
}
else{
res.smx = max({mx,x.smx,smx});
if(res.smx == mx) res.smxpos = mxpos;
else if(res.smx == smx) res.smxpos = smxpos;
else if(res.smx == x.smx) res.smxpos = x.smxpos;
}
}
return res;
}
};
struct Segment_tree{
int n;
vector<Node> nodes;
Segment_tree(const vector<Node> &arr){
n = arr.size() - 1;
nodes.resize(n * 4);
build(1,1,n,arr);
}
void pushup(int p){
nodes[p] = nodes[p<<1] + nodes[p<<1|1];
}
void build(int p,int l,int r,const vector<Node> &a){
if(l == r){
nodes[p] = a[l];
return;
}
int mid = (l + r) >> 1;
build(p<<1,l,mid,a);
build(p<<1|1,mid + 1,r,a);
pushup(p);
}
void update(int p,int l,int r,int d,const Node &x){
if(l == r && l == d){
nodes[p] = x;
return;
}
int mid = (l + r) >> 1;
if(mid >= d) update(p<<1,l,mid,d,x);
if(mid < d) update(p<<1|1,mid + 1,r,d,x);
pushup(p);
}
Node query(int p,int l,int r,int d,int b){
if(l >= d && r <= b){
return nodes[p];
}
int mid = (l + r) >> 1;
if(mid >= b) return query(p<<1,l,mid,d,b);
if(mid < d) return query(p<<1|1,mid + 1,r,d,b);
return query(p<<1,l,mid,d,b) + query(p<<1|1,mid + 1,r,d,b);
}
};
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int n,k;
cin>>n>>k;
vector<int> a(n + 1);
for(int i = 1;i <= n;i++) cin>>a[i];
vector<Node> nd(n + 1);
for(int i = 1;i <= n;i++){
nd[i].mx = a[i];
nd[i].mxpos = i;
}
Segment_tree t(nd);
vector<int> ans(n + 1,-1);
for(int i = 1;i <= n;i++){
auto [maxpos,maxn,smaxpos,smaxn] = t.query(1,1,n,i,min(n,i + k));
if(maxn == INT_MIN) continue;
if(ans[i-1] == maxn){
if(smaxn == INT_MIN) continue;
ans[i] = smaxn;
t.update(1,1,n,smaxpos,{0,INT_MIN,0,INT_MIN});
k -= smaxpos - i;
}
else{
ans[i] = maxn;
t.update(1,1,n,maxpos,{0,INT_MIN,0,INT_MIN});
k -= maxpos - i;
}
if(k < 0){
break;
}
}
for(int i = 1;i <= n;i++) cout<<ans[i]<<' ';
return 0;
}