• 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;
    }
    
  • 相关阅读:
    大伙看看这个界面风格咋样...
    unity 如何打开本地文件夹,并选中文件
    IoC模式(依赖、依赖倒置、依赖注入、控制反转)
    DOTween-Ease缓动函数
    unity 改变鼠标样式的两种方法
    Unity编辑器中分割线拖拽的实现
    根据日期计算星期几 -- 基姆拉尔森计算公式
    指派问题与匈牙利解法
    Unity游戏推送技术
    Unity图集打包
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/11124263.html
Copyright © 2020-2023  润新知