[HEOI2016/TJOI2016]排序

题目大意

给出一个\(1-n\)的排列,每次操作将\({[l_i,r_i]}\)上的数排序(\(opt=0\)升序,\(opt=1\)降序)

最后有一个询问第\(Q\)位上的数

解题思路

这题考虑用二分答案和线段树

设当前二分值为\(v\)

将排列中的数\(<v\)的设成\(0\),\(>=v\)的设成\(1\),丢给线段树(\(O(n)\)建树)

每次排序即统计这个区间内\(0\)和\(1\)的个数(相当于在线段树中的询问操作),再按照个数覆盖回去

操作完后查询第\(Q\)位上的数

若为\(1\),则答案\(>=v\)

若为\(0\),则答案\(<v\)

举个例子

给定排列1 6 2 5 3 4

当前二分值\(4\)

按上面的方式写成01序列变成0 1 0 1 0 1

此时对\([1,4]\)升序排列变成0 0 1 1 0 1

只要把\(1\)覆盖后面部分,\(0\)覆盖前面部分就完成了排序操作

可以用线段树区间修改维护

注意到,如果最终第\(Q\)位是1,表明这一位至少\(>=4\),这成为了我们继续二分的依据

#include<iostream>
#include<cstdio>
#include<cstring>

const int maxN=200000,Tsize=10000000;
int n,m,S[maxN],opt[maxN],l[maxN],r[maxN],Q;
int T[Tsize],tag[Tsize];

void build(int o,int l,int r,int v){
    if (l==r){
        T[o]=S[l]>=v;
        return;
    }
    int mdl=(l+r)>>1;
    build(o<<1,l,mdl,v);
    build(o<<1|1,mdl+1,r,v);
    T[o]=T[o<<1]+T[o<<1|1];
}

void pushdown(int now,int size){
    if (~tag[now]){
        T[now]=(tag[now])?size:0;
        tag[now<<1]=tag[now<<1|1]=tag[now];
        tag[now]=-1;
    }
}

int query(int o,int l,int r,int L,int R){
    if (l>r) return 0;
    if (l>R||r<L) return 0;
    pushdown(o,r-l+1);
    if (L<=l&&r<=R) return T[o];
    int mdl=(l+r)>>1;
    return query(o<<1,l,mdl,L,R)+query(o<<1|1,mdl+1,r,L,R);
}

int modify(int o,int l,int r,int L,int R,int v){
    if (l>r) return 0;
    pushdown(o,r-l+1);
    if (l>R||r<L) return T[o];
    if (L<=l&&r<=R){tag[o]=v;return (v)?(r-l+1):0;}
    int mdl=(l+r)>>1;
    return T[o]=modify(o<<1,l,mdl,L,R,v)+modify(o<<1|1,mdl+1,r,L,R,v);
}

int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&S[i]);
    for (int i=1;i<=m;i++) scanf("%d%d%d",&opt[i],&l[i],&r[i]);
    scanf("%d",&Q);
    int L=1,R=n,mdl;
    while (L<R){
        mdl=(L+R+1)>>1;
        memset(T,0,sizeof(T));
        memset(tag,-1,sizeof(tag));
        build(1,1,n,mdl);
        for (int i=1;i<=m;i++){
            int cnt=query(1,1,n,l[i],r[i]);
            if (opt[i]){
                modify(1,1,n,l[i],l[i]+cnt-1,1);
                modify(1,1,n,l[i]+cnt,r[i],0);
            }
            else{
                modify(1,1,n,l[i],r[i]-cnt,0);
                modify(1,1,n,r[i]-cnt+1,r[i],1);
            }
        }
        int now=query(1,1,n,Q,Q);
        if (now) L=mdl;
        else R=mdl-1;
    }
    printf("%d",L);
}

猜你喜欢

转载自www.cnblogs.com/ytxytx/p/9418127.html