训练日志9.11

 ​​​​​​P2824 [HEOI2016/TJOI2016] 排序

今天就写了这一题线段树+二分,qwq

我感觉这题主要难点在于将普通序列的排序转换成用01序列排序,用线段树维护01序列。

最后只询问第q位上的数,这个数是全排列中的数,有单调性,所以可以用二分答案,将大于等于mid的设为1,小于mid的设为0。

在进行m将排序后,如果第q位为1,则在[mid,r]中查找,如果第q位为0,则在[l,mid)中查找


#include<bits/stdc++.h>
#define ls id<<1
#define rs id<<1|1
using namespace std;
const int N=1e6;
int a[N],L[N],R[N];
int n,m;
int op[N];
int q;
struct tree{
    int l,r;
    int sum,tag;
}tr[N<<1];
void pushup(int id){
    tr[id].sum=tr[ls].sum+tr[rs].sum;
}
void pushdown(int id){
    if(tr[id].tag==-1)return ;
    tr[ls].sum=tr[id].tag*(tr[ls].r-tr[ls].l+1);
    tr[rs].sum=tr[id].tag*(tr[rs].r-tr[rs].l+1);
    tr[ls].tag=tr[rs].tag=tr[id].tag;
    tr[id].tag=-1;
}
void build(int id,int l,int r,int x){
    tr[id]={l,r,a[l]>=x,-1};
    if(l==r)return ;
    int mid=(l+r)>>1;
    build(ls,l,mid,x);
    build(rs,mid+1,r,x);
    pushup(id);
}
void mod(int id,int l,int r,int x){
    if(l>tr[id].r||r<tr[id].l)return ;
    if(l<=tr[id].l&&tr[id].r<=r){
        tr[id].sum=x*(tr[id].r-tr[id].l+1);
        tr[id].tag=x;
        return ;
    }
    pushdown(id);
    mod(ls,l,r,x);
    mod(rs,l,r,x);
    pushup(id);
}
int query(int id,int l,int r){
    if(l>tr[id].r||r<tr[id].l)return 0;
    if(l<=tr[id].l&&tr[id].r<=r)return tr[id].sum;
    pushdown(id);
    return query(ls,l,r)+query(rs,l,r);
}
int check(int x){
    build(1,1,n,x);
    for(int i=1;i<=m;i++){
        int l=L[i],r=R[i];
        int cnt=query(1,l,r);
        if(op[i]==0){
            mod(1,l,r-cnt,0);
            mod(1,r-cnt+1,r,1);
        }
        else{
            mod(1,l,l+cnt-1,1);
            mod(1,l+cnt,r,0);
        }
    }
    return query(1,q,q);
}
signed main(){

    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=m;i++)
        cin>>op[i]>>L[i]>>R[i];
    cin>>q;

    int l=0,r=n+1,ans(0);
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)){
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    cout<<ans<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值