zoukankan      html  css  js  c++  java
  • 【TJOI2016】【bzoj4552】排序(二分答案+线段树01排序)

    problem

    给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序

    排序分为两种
    1:(0,l,r)表示将区间[l,r]的数字升序排序
    2:(1,l,r)表示将区间[l,r]的数字降序排序

    最后询问第q位置上的数字。

    solution

    考虑二分答案
    对于mid
    1.将所有 >= mid 的数变成 1, < mid 的数变成 0 (01排序不影响排序结果,得到相对的大小关系)
    2.将处理过后的序列进行排序
    如果 q 这个位置上最后是 0 ,则 ans < mid ,我们就去找更小的值
    如果 q 这个位置上最后是 1, 则 ans >= mid,我们就去找更大的值

    这样原题就变成了01序列排序,可以用线段树logn维护
    假如说将 [l, r] 这段升序排列,
    算出 sum = find(l, r) 即 [l, r] 中 1 的个数
    维护排序的操作:
    change(r - sum + 1, r, 1); change(l, r - sum, 0);

    codes

    #include<cstdio>
    
    const int maxn = 100010;
    
    #define lch o<<1
    #define rch o<<1|1
    int _a[maxn], sgt[maxn<<2], tag[maxn<<2];
    void build(int o, int l, int r){
        tag[o] = -1;
        if(l == r){
            sgt[o] = _a[l];
            return ;
        }
        int mid = l+r>>1;
        build(lch,l,mid); build(rch,mid+1,r);
        sgt[o] = sgt[lch]+sgt[rch];
    }
    int pushdown(int o, int l, int r){
        if(tag[o] != -1){
            int mid = l+r>>1;
            sgt[lch] = (mid-l+1)*tag[o];
            sgt[rch] = (r-mid)*tag[o];
            tag[lch] = tag[rch] = tag[o];
            tag[o] = -1;
        }
    }
    int query(int o, int l, int r, int L, int R){
        if(r < L || l > R)return 0;
        if(L <= l && r <= R)return sgt[o];
        pushdown(o, l, r);
        int mid = l+r>>1, ans = 0;
        if(L <= mid)ans += query(lch, l, mid, L, R);
        if(R > mid)ans += query(rch, mid+1, r, L, R);
        return ans;
    }
    void change(int o, int l, int r, int L, int R, int v){
        if(r < L || l > R)return ;
        if(L <= l && r <= R){
            sgt[o] = (r-l+1)*v; tag[o] = v;
            return ;
        }
        pushdown(o,l,r);
        int mid = l+r>>1;
        if(L <= mid)change(lch, l, mid, L, R, v);
        if(R > mid)change(rch, mid+1, r, L, R, v);
        sgt[o] = sgt[lch]+sgt[rch];
    }
    
    int n, m, a[maxn], op[maxn], x[maxn], y[maxn], pos;
    int check(int _x){
        for(int i = 1; i <= n; i++)
            _a[i] = a[i]>=_x;
        build(1,1,n);
        for(int i = 1; i <= m; i++){
            int t = query(1,1,n,x[i],y[i]);
            if(op[i])change(1,1,n,x[i],x[i]+t-1,1),change(1,1,n,x[i]+t,y[i],0);
            else change(1,1,n,x[i],y[i]-t,0), change(1,1,n,y[i]-t+1,y[i],1);
        }
        return query(1,1,n,pos,pos);
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++)scanf("%d",&a[i]);
        for(int i = 1; i <= m; i++)scanf("%d%d%d",&op[i],&x[i],&y[i]);
        scanf("%d", &pos);
        int l = 1, r = n;
        while(l < r){
            int mid = l+r+1>>1;
            if(check(mid))l = mid;
            else r = mid-1;
        }
        printf("%d
    ", l);
        return 0;
    }
  • 相关阅读:
    组装query,query汇总,query字段
    POJ 1276, Cash Machine
    POJ 1129, Channel Allocation
    POJ 2531, Network Saboteur
    POJ 1837, Balance
    POJ 3278, Catch That Cow
    POJ 2676, Sudoku
    POJ 3126, Prime Path
    POJ 3414, Pots
    POJ 1426, Find The Multiple
  • 原文地址:https://www.cnblogs.com/gwj1314/p/9444858.html
Copyright © 2011-2022 走看看