BZOJ 4552 [Tjoi2016&Heoi2016]排序

来源:互联网 发布:js绑定事件的方法区别 编辑:程序博客网 时间:2024/06/09 16:10

BZOJ 4552 [Tjoi2016&Heoi2016]排序

题目描述

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


输入输出格式
输入格式:
输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。1 <= n, m <= 10^5第二行为n个整数,表示1到n的一个全排列。接下来输入m行,每一行有三个整数op, l, r, op为0代表升序排序,op为1代表降序排序, l, r 表示排序的区间。最后输入一个整数q,q表示排序完之后询问的位置, 1 <= q <= n。1 <= n <= 10^5,1 <= m <= 10^5


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


输入输出样例
输入样例#1: 
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
输出样例#1: 
5
说明
河北省选2016第一天第二题。原题的时限为6s,但是洛谷上是1s,所以洛谷的数据中,对于30%的数据,有 n,m<=1000,对于100%的数据,有 n,m<=30000


看起来很难搞,那就二分答案。
把小于等于二分数X的置为0,反之置为1,那么排序就成为将区间内前Len-sum位置为0,后sum位置为1,线段树解决。
其实就是个套路。


   
    #include <iostream>    #include <cstdio>    #include <cstring>    using namespace std;    const int MAXN=1e5+5,INF=0x3f3f3f3f;    struct Op{int L,R,Kind;}Q[MAXN];    int Sum[MAXN<<2],A[MAXN],N,M,Ql,Qr,Down[MAXN<<2],T[MAXN],Val,P;    inline void PushDown(int I,int L,int R)    {      if(Down[I]!=-1){        int Lc=I<<1,Rc=Lc|1,Mid=(L+R)>>1,Tag=Down[I];Down[I]=-1;        Down[Lc]=Down[Rc]=Tag;        Sum[Lc]=(Mid-L+1)*Tag,Sum[Rc]=(R-Mid)*Tag;      }    }    inline void PushUp(int I)    {      Sum[I]=Sum[I<<1]+Sum[I<<1|1];    }    void Build(int I,int L,int R)    {      if(L==R){Sum[I]=T[L];return;}      int Mid=(L+R)>>1;      Build(I<<1,L,Mid),Build(I<<1|1,Mid+1,R);      PushUp(I);    }    int Query(int I,int L,int R)    {      if(L>=Ql&&R<=Qr)return Sum[I];      PushDown(I,L,R);      int Lc=I<<1,Rc=Lc|1,Mid=(L+R)>>1;      if(Qr<=Mid)return Query(Lc,L,Mid);      else if(Ql>Mid)return Query(Rc,Mid+1,R);      else return Query(Lc,L,Mid)+Query(Rc,Mid+1,R);    }    void Update(int I,int L,int R)    {      if(L>=Ql&&R<=Qr){        Sum[I]=Val*(R-L+1);        Down[I]=Val;        return;      }      PushDown(I,L,R);      int Mid=(L+R)>>1,Lc=I<<1,Rc=Lc|1;      if(Qr<=Mid)Update(Lc,L,Mid);      else if(Ql>Mid)Update(Rc,Mid+1,R);      else Update(Lc,L,Mid),Update(Rc,Mid+1,R);      PushUp(I);    }    inline int Check(int X)    {      for(int I=1;I<=N;++I)        T[I]=(A[I]<=X)?0:1;      memset(Down,-1,sizeof(Down));      Build(1,1,N);      for(int I=1,T;I<=M;++I){        Ql=Q[I].L,Qr=Q[I].R;        T=Query(1,1,N);        if(Q[I].Kind==0){          Ql=Q[I].L,Qr=Q[I].R-T,Val=0;          if(Ql<=Qr)Update(1,1,N);          Ql=Q[I].R-T+1,Qr=Q[I].R,Val=1;          if(Ql<=Qr)Update(1,1,N);        }else{          Ql=Q[I].L,Qr=Q[I].L+T-1,Val=1;          if(Ql<=Qr)Update(1,1,N);          Ql=Q[I].L+T,Qr=Q[I].R,Val=0;          if(Ql<=Qr)Update(1,1,N);        }      }      Ql=P,Qr=P;      return Query(1,1,N);    }    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",&Q[I].Kind,&Q[I].L,&Q[I].R);      scanf("%d",&P);      int L=1,R=N,Mid;      while(L<=R){        Mid=(L+R)>>1;        if(!Check(Mid))R=Mid-1;        else L=Mid+1;      }      printf("%d\n",R+1);      return 0;    }