版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题意:在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。
这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:
1:(0,l,r)表示将区间[l,r]的数字升序排序
2:(1,l,r)表示将区间[l,r]的数字降序排序
最后询问第q位置上的数字。
思路 这道题常规思路是直接暴力 (当然超时是肯定的)
于是在这里我么考虑将答案二分 然后将原序列转为储存元素与该值大小关系的 01序列。然后考虑01序列排序,这个是可以O(logn)实现的。只需要对序列建线段树,然后统计区间 1
的个数,并按序区间赋值即可。查询的时候直接线段树单点询P 位置的元素是否为 1 以调整二分上下界。
上代码`
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+1000;
#define lc (p<<1)
#define rc (p<<1|1)
inline int read()
{
int data=0;int w=1; char ch=0;
ch=getchar();
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return data*w;
}
int n,m;
int a[N],pos;
struct opt{
int l,r,op;
opt() {}
opt(int _l, int _r, int _op) : l(_l), r(_r), op(_op){}
}q[N];
struct node{
int p,l,r,sum,tag;
}t[N<<2];
inline void pushup(int p){t[p].sum=t[lc].sum+t[rc].sum;}
inline void pushdown(int p,int l,int r){
if(~t[p].tag){
t[lc].tag=t[rc].tag=t[p].tag;
int mid=(l+r)>>1;
if(t[p].tag) t[lc].sum=mid-l+1,t[rc].sum=r-mid;
else t[lc].sum=t[rc].sum=0;
t[p].tag=-1;
}
}
inline void build(int p,int l,int r,int x){
t[p].l=l;t[p].r=r;t[p].tag=-1;
if(l==r) {
t[p].sum=(a[l]>=x);return;
}
int mid=(l+r)>>1;
build(lc,l,mid,x);build(rc,mid+1,r,x);pushup(p);
}
inline int query(int p,int L,int R){
int l=t[p].l,r=t[p].r;
if(L>r||R<l) return 0;
if(l>=L&&r<=R) return t[p].sum;
pushdown(p,l,r);
int mid=(l+r)>>1;
int res=0;
if(L<=mid) res+=query(lc,L,R);
if(R>mid) res+=query(rc,L,R);
return res;
}
inline int que(int p,int pos){
int l=t[p].l,r=t[p].r;
if(l==r) return t[p].sum;
pushdown(p,l,r);
int mid=(l+r)>>1;
if(pos<=mid) return que(lc,pos);
else return que(rc,pos);
}
inline void modify(int p,int L,int R,int x){
int l=t[p].l,r=t[p].r;
if(l>=L&&r<=R) {
t[p].sum=x*(r-l+1);t[p].tag=x;return;
}
pushdown(p,l,r);
int mid=(l+r)>>1;
if(L<=mid) modify(lc,L,R,x);
if(R>mid) modify(rc,L,R,x);
pushup(p);
}
bool check(int x){
build(1,1,n,x);
for(register int i=1;i<=m;i++){
int len=query(1,q[i].l,q[i].r);
if(!q[i].op){
modify(1,q[i].l,q[i].r-len,0);
modify(1,q[i].r-len+1,q[i].r,1);
}
else{
modify(1,q[i].l,q[i].l+len-1,1);
modify(1,q[i].l+len,q[i].r,0);
}
}
return que(1,pos);
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=m;i++){int op=read(),l=read(),r=read();q[i]=opt(l,r,op);}
pos=read();
int l=1,r=n,ans;
while(l<r){
int mid=(l+r)>>1;
if(check(mid)) ans=mid,l=mid+1;
else r=mid;
}
printf("%d\n",ans);
return 0;
}