P2824 [HEOI2016/TJOI2016] 排序 题解

有点想不到的trick

题目有两个操作,分别是对 \([l,r]\) 区间进行升序和降序排序,在最后询问某个位置 \(q\) 上的值是多少。

真的去对一个序列做排序会让复杂度很难看,但如果是给一个 \(01\) 序列排序是比较轻松的,记录一下 \(1\) 的个数,每次1操作就可以用两次区间覆盖来代替,又因为最终的询问只有一次,所以考虑这样一个做法:

二分一个答案 \(mid\) 并将原序列以 \(\geq mid\) 的值设为 \(1\) 其余设为 \(0\) 的方式变成 \(01\) 序列,并在操作完成后检查 \(q\) 上的值是不是 \(1\)

这个东西的单调性可以被满足是因为,如果当前 \(q\) 上的值大于 \(mid\),那么 \(mid\) 取更大值时 \(q\) 也可能大于等于 \(mid\)。而小于 \(mid\) 则肯定不会再取到更大的值,最终二分到 \(q\) 位置上是 \(1\),关系取等号的 \(mid\) 就是答案。

点击查看代码
using namespace std;
const int N=1e5+5;
int n,m,a[N],q;
int P=1,DEP;
struct {
    int opt,l,r;
}que[N];
struct {
    int sum,tag;
    bool chk;
}t[N*3];
ili void pushdown(int i,int siz){
    siz>>=1;
    if(t[i].chk){
        t[ls(i)].sum=siz*t[i].tag;
        t[rs(i)].sum=siz*t[i].tag;
        t[ls(i)].tag=t[i].tag;
        t[rs(i)].tag=t[i].tag;
        t[ls(i)].chk=1;
        t[rs(i)].chk=1;
        t[i].chk=0;
    }
}
ili void update(int l,int r,int v){
    l=l+P-1,r=r+P+1;
    int siz=1;
    for(int i=DEP;i;i--) pushdown(l>>i,1<<i),pushdown(r>>i,1<<i);
    while(l^1^r){
        if(~l&1){
            t[l^1].sum=siz*v,t[l^1].chk=1,t[l^1].tag=v;
        }
        if(r&1){
            t[r^1].sum=siz*v,t[r^1].chk=1,t[r^1].tag=v;
        }
        l>>=1,r>>=1,siz<<=1;
        t[l].sum=t[ls(l)].sum+t[rs(l)].sum;
        t[r].sum=t[ls(r)].sum+t[rs(r)].sum;
    }
    for(l>>=1;l;l>>=1) t[l].sum=t[ls(l)].sum+t[rs(l)].sum;
}
ili int query(int l,int r){
    l=l+P-1,r=r+P+1;
    int res=0;
    for(int i=DEP;i;i--) pushdown(l>>i,1<<i),pushdown(r>>i,1<<i);
    while(l^1^r){
        if(~l&1) res+=t[l^1].sum;
        if(r&1) res+=t[r^1].sum;
        l>>=1,r>>=1;
    }
    return res;
}
int check(int mid){
    for(int i=1;i<=n;i++){
        t[i+P].sum=(mid<=a[i]);
        t[i+P].chk=0;
    }
    for(int i=P-1;i;i--){
        t[i].chk=0;
        t[i].sum=t[ls(i)].sum+t[rs(i)].sum;
    }
    for(int i=1;i<=m;i++){
        int opt=que[i].opt,l=que[i].l,r=que[i].r;
        int sum=query(l,r);
        if(opt==0){
            sum=r-l+1-sum;//0的个数
            update(l,l+sum-1,0);
            update(l+sum,r,1);
        }else{
            update(l,l+sum-1,1);
            update(l+sum,r,0);
        }
    }
    return query(q,q);
}
void xpigeon(){
    rd(n,m);
    for(int i=1;i<=n;i++){
        rd(a[i]);
    }
    for(int i=1;i<=m;i++){
        rd(que[i].opt,que[i].l,que[i].r);
    }
    rd(q);
    while(P<=n+1) P<<=1,DEP++;
    int L=0,R=n+1;
    int ans=-1;
    while(R-L>1){
        int mid=(L+R)>>1;
        if(check(mid)){
            ans=mid;
            L=mid;
        }else{
            R=mid;
        }
    }
    cout<<ans<<'\n';
}
posted @ 2025-09-05 21:48  香香的鸽子  阅读(13)  评论(0)    收藏  举报