题目描述
在 20162016 年,佳媛姐姐喜欢上了数字序列。因而她经常研究关于序列的一些奇奇怪怪的问题,现在她在研究一个难题,需要你来帮助她。
这个难题是这样子的:给出一个 11 到 nn 的排列,现在对这个排列序列进行 mm 次局部排序,排序分为两种:
0 l r 表示将区间 [l,r][l,r] 的数字升序排序
1 l r 表示将区间 [l,r][l,r] 的数字降序排序
注意,这里是对下标在区间 [l,r][l,r] 内的数排序。
最后询问第 qq 位置上的数字。
输入格式
输入数据的第一行为两个整数 nn 和 mm,nn 表示序列的长度,mm 表示局部排序的次数。
第二行为 nn 个整数,表示 11 到 nn 的一个排列。
接下来输入 mm 行,每一行有三个整数 \text{op},l,rop,l,r,\text{op}op 为 00 代表升序排序,\text{op}op 为 11 代表降序排序, l,rl,r 表示排序的区间。
最后输入一个整数 qq,表示排序完之后询问的位置
输出格式
输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第 qq 位置上的数字。
输入输出样例
输入 #1复制
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
输出 #1复制
5
说明/提示
河北省选2016第一天第二题。
对于 30%30% 的数据,n,m\leq 1000n,m≤1000
对于 100%100% 的数据,n,m\leq 10^5n,m≤10
5
,1\leq q\leq n1≤q≤n
我们不能每次都直接排序,但是我们如果是0,1排序呢?只需要log就可以了。就是直接线段树从新排列,然后这道题如果我们二分一个数字,那么把大于等于的置为1,小于等于的置为0就可以了。
然后判断位置q是否为1即可。
为什么具有二分性呢?可以简单地假设一下,如果你二分的答案是1,那么原序列所有的值都转化为了1,所以最后肯定是true。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n,m,op[N],l[N],r[N],a[N],b[N],L,R,k;
struct node{int l,r,sum,lazy;}t[N<<2];
inline void push_up(int p){t[p].sum=t[p<<1].sum+t[p<<1|1].sum;}
inline void push_down(int p){
if(t[p].lazy!=-1){
t[p<<1].lazy=t[p<<1|1].lazy=t[p].lazy;
t[p<<1].sum=(t[p<<1].r-t[p<<1].l+1)*t[p].lazy;
t[p<<1|1].sum=(t[p<<1|1].r-t[p<<1|1].l+1)*t[p].lazy;
t[p].lazy=-1;
}
}
void build(int p,int l,int r){
t[p].l=l; t[p].r=r; t[p].lazy=-1;
if(l==r) return void(t[p].sum=b[l]);
int mid=l+r>>1;
build(p<<1,l,mid); build(p<<1|1,mid+1,r);
push_up(p);
}
void change(int p,int l,int r,int v){
if(t[p].l==l&&t[p].r==r){t[p].sum=(r-l+1)*v; t[p].lazy=v; return ;}
int mid=t[p].l+t[p].r>>1; push_down(p);
if(r<=mid) change(p<<1,l,r,v);
else if(l>mid) change(p<<1|1,l,r,v);
else change(p<<1,l,mid,v),change(p<<1|1,mid+1,r,v);
push_up(p);
}
int ask(int p,int l,int r){
if(t[p].l==l&&t[p].r==r) return t[p].sum;
push_down(p); int mid=t[p].l+t[p].r>>1;
if(r<=mid) return ask(p<<1,l,r);
else if(l>mid) return ask(p<<1|1,l,r);
else return ask(p<<1,l,mid)+ask(p<<1|1,mid+1,r);
}
inline int check(int mid){
for(int i=1;i<=n;i++) b[i]=a[i]>=mid; build(1,1,n);
for(int i=1;i<=m;i++){
int num=ask(1,l[i],r[i]);
if(op[i]){
if(num) change(1,l[i],l[i]+num-1,1);
if(num!=r[i]-l[i]+1) change(1,l[i]+num,r[i],0);
}else{
if(num) change(1,r[i]-num+1,r[i],1);
if(num!=r[i]-l[i]+1) change(1,l[i],r[i]-num,0);
}
}
return ask(1,k,k);
}
signed main(){
cin>>n>>m; L=1,R=n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>op[i]>>l[i]>>r[i]; cin>>k;
while(L<R){
int mid=L+R+1>>1;
if(check(mid)) L=mid;
else R=mid-1;
}
cout<<L<<endl;
return 0;
}