[bzoj4552][Tjoi2016][Heoi2016]排序

Description

给出一个的全排列,现在对这个全排列序列进行次局部排序,排序分为种:

表示将区间的数字升序排序;

表示将区间的数字降序排序.

最后询问第位置上的数字.

Input

行为两个整数.表示序列的长度,表示局部排序的次数.

行为个整数,表示的一个全排列.

接下来输入行,每行有个整数

代表升序排序,为1代表降序排序;表示排序的区间.

最后输入一个整数,表示排序完之后询问的位置.

Output

输出数据仅有一行一个整数,表示按照顺序将全部的部分排序结束后第位置上的数字.

Sample Input

6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3

Sample Output

5

HINT

Solution

二分答案.

的位置标为,其余标为.

线段树维护排序操作,最后判断位置上是否为.

#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 100005
#define M 300005
using namespace std;
struct linetree{
    int l,r,t,op;
}lt[M];
struct quest{
    int op,l,r;
}b[N];
int a[N],n,m,q,t,l,r,mid;
inline void build(int u,int l,int r,int k){
    lt[u].l=l;lt[u].r=r;lt[u].op=0;
    if(lt[u].l<lt[u].r){
        int lef=u<<1,rig=u<<1|1;
        int mid=(lt[u].l+lt[u].r)>>1;
        build(lef,l,mid,k);build(rig,mid+1,r,k);
        lt[u].t=lt[lef].t+lt[rig].t;
    }
    else if(a[lt[u].l]>=k) lt[u].t=0;
    else lt[u].t=1;
}
inline void cover(int u,int i){
    if(lt[u].l>=b[i].l&&lt[u].r<=b[i].r){
        if(!b[i].op){
            lt[u].op=-1;
            if(lt[u].l-b[i].l+1<=t){
                lt[u].t=min(t-(lt[u].l-b[i].l),lt[u].r-lt[u].l+1);
            }
            else lt[u].t=0;
        }
        else{
            lt[u].op=1;
            if(b[i].r-lt[u].r+1<=t){
                lt[u].t=min(t-(b[i].r-lt[u].r),lt[u].r-lt[u].l+1);
            }
            else lt[u].t=0;
        }
    }
    else if(lt[u].l<lt[u].r){
        int lef=u<<1,rig=u<<1|1;
        int mid=(lt[u].l+lt[u].r)>>1;
        if(lt[u].op>0)/*降序*/{
            lt[u].op=0;lt[lef].op=lt[rig].op=1;
            lt[rig].t=min(lt[u].t,lt[rig].r-lt[rig].l+1);
            lt[lef].t=lt[u].t-lt[rig].t;
        }
        else if(lt[u].op<0)/*升序*/{
            lt[u].op=0;lt[lef].op=lt[rig].op=-1;
            lt[lef].t=min(lt[u].t,lt[lef].r-lt[lef].l+1);
            lt[rig].t=lt[u].t-lt[lef].t;
        }
        if(b[i].l<=mid) cover(lef,i);
        if(b[i].r>mid) cover(rig,i);
        lt[u].t=lt[lef].t+lt[rig].t;
    }
}
inline int ask(int u,int l,int r){
    if(lt[u].l>=l&&lt[u].r<=r)
        return lt[u].t;
    if(lt[u].l<lt[u].r){
        int lef=u<<1,rig=u<<1|1,ret=0;
        int mid=(lt[u].l+lt[u].r)>>1;
        if(lt[u].op>0)/*降序*/{
            lt[u].op=0;lt[lef].op=lt[rig].op=1;
            lt[rig].t=min(lt[u].t,lt[rig].r-lt[rig].l+1);
            lt[lef].t=lt[u].t-lt[rig].t;
        }
        else if(lt[u].op<0)/*升序*/{
            lt[u].op=0;lt[lef].op=lt[rig].op=-1;
            lt[lef].t=min(lt[u].t,lt[lef].r-lt[lef].l+1);
            lt[rig].t=lt[u].t-lt[lef].t;
        }
        if(l<=mid) ret+=ask(lef,l,r);
        if(r>mid) ret+=ask(rig,l,r);
        return ret;
    }
}
inline bool chk(int k){
    build(1,1,n,k);
    for(int i=1;i<=m;++i){
        t=ask(1,b[i].l,b[i].r);cover(1,i);
    }
    return !ask(1,q,q);
}
inline void init(){
    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",&b[i].op,&b[i].l,&b[i].r);
    scanf("%d",&q);
    l=1;r=n;
    while(l<r){
        mid=(l+r+1)>>1;
        if(chk(mid)) l=mid;
        else r=mid-1;
    }
    printf("%d\n",l);
}
int main(){
    freopen("sort.in","r",stdin);
    freopen("sort.out","w",stdout);
    init();
    fclose(stdin);
    fclose(stdout);
    return 0;
}
时间: 2024-10-10 09:01:19

[bzoj4552][Tjoi2016][Heoi2016]排序的相关文章

bzoj4552 [Tjoi2016&amp;Heoi2016]排序

Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q位置上的数字. Input 输入数据的第一行为两个整数n和m.n表示序列的长度,m表示局部排序的次数.1 <= n, m <= 10^5第二

bzoj4552 [Tjoi2016&amp;Heoi2016]排序 (线段树+二分)

题意:一个1~n的排列,m个操作: 0 x y:将ax~ay按升序排列: 1 x y:将ax~ay按降序排列. 询问m次操作后第aq的值. 输入:第一行:两个正整数n,m,表示序列的长度与询问的个数: 第二行:一个1~n的排列: 第3~m+2行:每行一个操作. 第m+3行:一个数q表示询问的位置. 输出:一个数表示aq的值. 样例输入: 6 3 1 6 2 5 3 4 0 1 4 1 3 6 0 2 4 3 样例输出: 5 解析:考虑二分答案,将小于答案的数变为0,将大于等于答案的变为1,这样整

4552: [Tjoi2016&amp;Heoi2016]排序

4552: [Tjoi2016&Heoi2016]排序 Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q 位置上的数字. Input 输入数据的第一行为两个整数n和m.n表示序列的长度,

[BZOJ] 4552: [Tjoi2016&amp;Heoi2016]排序 #二分+线段树+算法设计策略

4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1451  Solved: 734[Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,r

bzoj 4552: [Tjoi2016&amp;Heoi2016]排序

Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q 位置上的数字. Input 输入数据的第一行为两个整数n和m.n表示序列的长度,m表示局部排序的次数.1 <= n, m <= 10^

[bzoj4552][TJOI&amp;HEOI2016]排序

题目大意 有一个n的排列,进行m次操作,每次操作是将一个区间升序或降序排序. 请你输出m次操作后第p个位置的值. 二分答案 题解好机智! 我们二分答案x,然后就是判断a[p]>=x? 把原序列转化为01序列,0表示小于x,1表示大于等于x. 那么区间升序排序其实就是把0全放前面,1都放后面. 用线段树兹瓷区间赋值就好了. 然后只需要维护区间0的个数. #include<cstdio> #include<algorithm> #define fo(i,a,b) for(i=a;

bzoj 4552 [Tjoi2016&amp;Heoi2016]排序——二分答案

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 二分答案,把 >= mid 的设成1.< mid 的设成0,之后排序就变成区间赋值了. #include<cstdio> #include<cstring> #include<algorithm> #define ls Ls[cr] #define rs Rs[cr] using namespace std; const int N=1e5+5,

bzoj4552【TJOI2016&amp;HEOI2016】排序

4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MB Submit: 291  Solved: 171 [Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,

Bzoj4556: [Tjoi2016&amp;Heoi2016]字符串 后缀数组

4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 169  Solved: 87[Submit][Status][Discuss] Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了 一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE O,嫁给高富帅,走上人生巅峰.