<h2>题目描述</h2>
对一个长度为 $n$ 的排列进行 $m$ 次如下操作:
- 将区间 $[l,r]$ 中的数字升序排序。
- 将区间 $[l,r]$ 中的数字降序排序
最后输出位置 $p$ 的数字。
其中 $1 \leq n,m \leq 10^5$
<h2>解题报告</h2>
发现询问只有一组,我们可以考虑二分答案。
考虑二分答案 $p$ 表示该输出的答案。因为这是一个排列,所以我们可以把小于 $p$ 的数标记为 $0$ ,大于 $p$ 的数标记为 $1$ ,线段树维护一下区间覆盖和求和,最后检验一下位置是 $0$ 还是 $1$ 就可以了。
升序排序相当于把 $1$ 放到后边,降序排序则是放到前边。
如果二分后位置是 $0$ 的话显然正确答案比二分的答案要更大,是 $1$ 的话则要小,因为二分成立当且仅当这个位置的数是 $1$。
#include <iostream>
#include <cstring>
#include <cstdio>
#define FOR(i,a,b) for(register int i = a;i <= b;++i)
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
const int MAXN = 100000 + 5;
struct SegmentTree New(int ,int ,SegmentTree ,SegmentTree *);
struct SegmentTree{
int l,r,sum,tag;
SegmentTree lc,rc;
static SegmentTree *build(int l,int r){
int mid = (l + r) >> 1;
return (l == r) ? New(l,r,NULL,NULL) : New(l,r,build(l,mid),build(mid+1,r));
}
inline void pushup(){
sum = lc->sum + rc->sum;
}
inline void cover(int delta){
sum = (r-l+1)*delta;
tag = delta;
}
inline void pushdown(){
if(tag != -1){
lc->cover(tag);
rc->cover(tag);
tag = -1;
}
}
void modify(int L,int R,int x){
if(L == l && R == r){
cover(x);
return;
}
pushdown();
int mid = (l + r) >> 1;
if(R <= mid) lc->modify(L,R,x);
else if(L > mid) rc->modify(L,R,x);
else lc->modify(L,mid,x),rc->modify(mid+1,R,x);
pushup();
}
int query(int L,int R){
if(L == l && R == r) return sum;
pushdown();
int mid = (l + r) >> 1;
if(R <= mid) return lc->query(L,R);
else if(L > mid) return rc->query(L,R);
return lc->query(L,mid) + rc->query(mid+1,R);
}
}pool[MAXN<<2],frog = pool,segt;
SegmentTree New(int l,int r,SegmentTree lc,SegmentTree *rc){
SegmentTree *ret = ++frog;
ret->l = l;ret->r = r;
ret->lc = lc;ret->rc = rc;
ret->sum = 0;ret->tag = -1;
return ret;
}
int N,M;
int a[MAXN],pos;
struct Data{
int l,r,opt;
}d[MAXN];
inline bool check(int k){ // Answer_pos >= k_pos ?
FOR(i,1,N) segt->modify(i,i,(a[i] >= k) ? 1 : 0);
FOR(i,1,M){
int l = d[i].l,r = d[i].r,opt = d[i].opt;
int t = segt->query(d[i].l,d[i].r); // 1
// printf("%d %d %d %dn",l,r,opt,t);
//DEBUG(l);DEBUG(r);DEBUG(t);
if(opt){
if(l <= l+t-1) segt->modify(l,l+t-1,1);
if(l+t <= r) segt->modify(l+t,r,0);
// [l,l+t-1]:1 [l+t,r]:0
}
else{ // 31 37 1 7
if(l <= r-t) segt->modify(l,r-t,0);
if(r-t+1 <= r) segt->modify(r-t+1,r,1);
// [l,r-t]:0 [r-t+1,r]:1
}
}
int ans = segt->query(pos,pos);
return ans == 1;
}
int main(){
scanf("%d%d",&N,&M);
segt = SegmentTree::build(1,N);
FOR(i,1,N) scanf("%d",a+i);
FOR(i,1,M) scanf("%d%d%d",&d[i].opt,&d[i].l,&d[i].r);
scanf("%d",&pos);
int l = 1,r = N,ans;
while(l <= r){
// DEBUG(l);DEBUG(r);
int mid = (l + r) >> 1;
if(check(mid)) l = mid+1,ans = mid;
else r = mid - 1;
}
printf("%dn",ans);
return 0;
}