bzoj 4552 [Tjoi2016&Heoi2016]排序 (二分答案 线段树)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4552

题意:

给你一个1-n的全排列,m次操作,操作由两种:1.将[l,r]升序排序,2.将[l,r]降序排列

最后给你一个点p,输出这个点的数

思路:

因为这道题只有一个询问,只需要知道一个位置的值,且序列是全排列,那么我们可以对答案进行二分,首先我们先选定一个值x,将数组中比x大的全部变成1,小于等于x的变为0,然后用线段树去模拟排序的操作,最后我们需要查询p位置的数如果为1那么代表答案大于当前数x,为0代表答案小于当前数x,继续二分就好了

实现代码:

#include<bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid int m = (l + r) >> 1
const int M = 1e5 +10;
int sum[M<<2],flag[M<<2],lazy[M<<2],a[M],b[M],op[M];
struct node{
    int l,r;
}q[M];

void pushup(int rt){
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}

void pushdown(int l,int r,int rt){
    if(flag[rt]){
        mid;
        sum[rt<<1] = lazy[rt]*(m-l+1);
        sum[rt<<1|1] = lazy[rt]*(r-m);
        lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
        flag[rt<<1] = flag[rt<<1|1] = flag[rt];
        flag[rt] = 0;
    }
}

void build(int l,int r,int rt){
    flag[rt] = 0; lazy[rt] = 0;
    if(l == r){
        sum[rt] = b[l];
        return;
    }
    mid;
    build(lson); build(rson);
    pushup(rt);
}

void update(int L,int R,int c,int l,int r,int rt){
    if(L <= l&&R >= r){
        sum[rt] = c*(r-l+1);
        lazy[rt] = c; flag[rt] = 1;
        return ;
    }
    pushdown(l,r,rt);
    mid;
    if(L <= m) update(L,R,c,lson);
    if(R > m) update(L,R,c,rson);
    pushup(rt);
}

int query(int L,int R,int l,int r,int rt){
    if(L <= l&&R >= r){
        return sum[rt];
    }
    pushdown(l,r,rt);
    mid;
    int ret = 0;
    if(L <= m) ret += query(L,R,lson);
    if(R > m) ret += query(L,R,rson);
    return ret ;
}

int main()
{
    int n,k,pos;
    scanf("%d%d",&n,&k);
    for(int i = 1;i <= n;i ++)
        scanf("%d",&a[i]);
    for(int i = 1;i <= k;i ++)
        scanf("%d%d%d",&op[i],&q[i].l,&q[i].r);
    scanf("%d",&pos);
    int l = 1,r = n;
    while(l < r){
        mid;
        for(int i = 1;i <= n;i ++){
            if(a[i] > m) b[i] = 1;
            else b[i] = 0;
        }
        build(1,n,1);
        for(int i = 1;i <= k;i ++){
            int cnt = query(q[i].l,q[i].r,1,n,1);
            if(op[i]){  //降序排列,1放在前面,0放在后面
                if(cnt) update(q[i].l,q[i].l+cnt-1,1,1,n,1);
                if(cnt+q[i].l <= q[i].r) update(q[i].l+cnt,q[i].r,0,1,n,1);
            }
            else{  //升序排序,1放在后面,0放在前面
                if(cnt) update(q[i].r-cnt+1,q[i].r,1,1,n,1);
                if(q[i].r-cnt >= q[i].l) update(q[i].l,q[i].r-cnt,0,1,n,1);
            }
        }
        if(query(pos,pos,1,n,1)) l = m+1;
        else r = m;
    }
    printf("%d
",l);
    return 0;
}