LOJ504「LibreOJ β Round」ZQC 的手办

https://loj.ac/problem/504

题解

对于区间取\(\max\),这个比较好办,直接在线段树上打标记就行了。

如果让我们弹出前\(n\)个数,我们可以用类似超级钢琴的思想,队列中每个元素是一个线段树节点,弹出时记录最值的位置,然后分成两半继续做就行了。

代码

#include<bits/stdc++.h>
#define N 500009
using namespace std;
typedef long long ll;
int n,a[N],m;
int tr[N<<2],pos[N<<2],la[N<<2];
int ans[N],top;
bool tag[N<<2];
inline ll rd(){
  ll x=0;char c=getchar();bool f=0;
  while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
  return f?-x:x;
}
struct node{
  int nw,l,r;
  inline bool operator <(const node &b)const{
    return tr[nw]>tr[b.nw];
  }
};
priority_queue<node>q;
inline void pushup(int cnt){
  tr[cnt]=tr[cnt<<1];pos[cnt]=pos[cnt<<1];
  if(tr[cnt<<1|1]<tr[cnt])tr[cnt]=tr[cnt<<1|1],pos[cnt]=pos[cnt<<1|1];
}
inline void pushdown(int cnt){
  la[cnt<<1]=max(la[cnt<<1],la[cnt]);
  la[cnt<<1|1]=max(la[cnt<<1|1],la[cnt]);
  tr[cnt<<1]=max(tr[cnt<<1],la[cnt]);
  tr[cnt<<1|1]=max(tr[cnt<<1|1],la[cnt]);
  la[cnt]=0;
}
void build(int cnt,int l,int r){
  if(l==r){
    pos[cnt]=l;
    tr[cnt]=a[l];
    tag[cnt]=1;
    return;
  }
  int mid=(l+r)>>1;
  build(cnt<<1,l,mid);
  build(cnt<<1|1,mid+1,r);
  pushup(cnt);
}
void upd(int cnt,int l,int r,int L,int R,int x){
  if(l>=L&&r<=R){
    tr[cnt]=max(tr[cnt],x);
    la[cnt]=max(la[cnt],x);
    return;
  }
  int mid=(l+r)>>1;
  if(la[cnt])pushdown(cnt);
  if(mid>=L)upd(cnt<<1,l,mid,L,R,x);
  if(mid<R)upd(cnt<<1|1,mid+1,r,L,R,x);
  pushup(cnt);
}
void query(int cnt,int l,int r,int L,int R){
  if(l>=L&&r<=R){
    q.push(node{cnt,l,r});
    return;
  }
  int mid=(l+r)>>1;
  if(la[cnt])pushdown(cnt);
  if(mid>=L)query(cnt<<1,l,mid,L,R);
  if(mid<R)query(cnt<<1|1,mid+1,r,L,R);
}
int main(){
  n=rd();
  for(int i=1;i<=n;++i)a[i]=rd(); 
  build(1,1,n);
  m=rd();
  int opt,l,r,k,x;
  while(m--){
    opt=rd();l=rd();r=rd();k=rd();
    if(opt==1){
      upd(1,1,n,l,r,k);
    }
    else{
      x=rd();
      while(!q.empty())q.pop();
      query(1,1,n,l,r);
      for(int i=1;i<=x;++i){
        if(q.empty())break;
        int cnt=q.top().nw;
        node y=q.top();q.pop();
        if(tr[cnt]>=k)break;
        ans[++top]=tr[cnt];
        if(tag[cnt])continue;
        pushdown(cnt);
        if(y.l<=pos[cnt]-1)query(cnt,y.l,y.r,y.l,pos[cnt]-1);
        if(pos[cnt]+1<=y.r)query(cnt,y.l,y.r,pos[cnt]+1,y.r);
      }
      if(top==x){for(int i=1;i<=top;++i)printf("%d ",ans[i]);puts("");}
      else puts("-1");
      top=0;
    }
  }
  return 0;
}

转载于:https://www.cnblogs.com/ZH-comld/p/11124263.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值