题意
n
n
n个数的排列,对这个排列进行
m
m
m次局部排序
0 l r升序排序,1 l r 降序排序
最后询问第
p
o
s
pos
pos个位置上的数是多少
分析
将当前序列变成01串,使用线段树维护01串。使用二分答案的方式进行求解。
对于每次二分的答案,大于等于
m
i
d
mid
mid的元素置为1,小于等于
m
i
d
mid
mid的元素置为0。
使用线段树维护每次修改的操作,设当前
[
l
,
r
]
[l,r]
[l,r]中1个个数为
n
u
m
num
num:
升序排序:将
[
r
−
n
u
m
+
1
,
r
]
[r-num+1,r]
[r−num+1,r]置1,
[
l
,
r
−
m
u
l
]
[l,r-mul]
[l,r−mul]置0
降序排序:将
[
l
,
l
+
n
u
m
−
1
]
[l,l+num-1]
[l,l+num−1]置1,
[
l
+
n
u
m
,
r
]
[l+num,r]
[l+num,r]置0
最后检测当前
p
o
s
pos
pos上的元素是否是1
为什么可以二分?
枚举
m
i
d
mid
mid时,
m
i
d
mid
mid变小,1个个数越来越多,约逼近答案。
m
i
d
=
1
mid=1
mid=1时,序列中元素均为
1
1
1。
代码
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <iomanip>
#include <map>
#include <cstdio>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int ,int > pii;
#define endl '\n'
ll gcd(ll a, ll b){
return b == 0 ? a : gcd(b, a % b);
}
void input(){
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
}
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
const int N = 1e6+10, M = N * 2, inf = 1e8;
int n, m, a[N], b[N], pos;
struct Node{
int l, r, sum, lazy;
// l r 为左右端点,sum是区间和,lazy是懒标记
// lazy初始值为-1,表示当前区间无懒标记
}tr[N];
void pushup(int u){
tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum;
}
void pushdown(int u){
if(tr[u].lazy != -1){
tr[u<<1].lazy = tr[u<<1|1].lazy = tr[u].lazy;
tr[u<<1].sum = (tr[u<<1].r - tr[u<<1].l + 1) * tr[u].lazy;
tr[u<<1|1].sum = (tr[u<<1|1].r - tr[u<<1|1].l + 1) * tr[u].lazy;
tr[u].lazy = -1;
}
}
void build(int u, int l, int r){
tr[u].l = l, tr[u].r = r, tr[u].lazy = -1;
if(l == r){
tr[u].sum = b[l];
}else{
int mid = (l + r) >> 1;
build(u<<1, l, mid);
build(u<<1|1, mid + 1, r);
pushup(u);
}
}
void update(int u, int l, int r, int v){
if(l <= tr[u].l && tr[u].r <= r){
tr[u].lazy = v;
tr[u].sum = (tr[u].r - tr[u].l + 1) * v;
}else{
int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u);
if(l <= mid) update(u<<1, l, r, v);
if(r > mid) update(u<<1|1, l, r, v);
pushup(u);
}
}
int query(int u, int l, int r){
if(l <= tr[u].l && tr[u].r <= r){
return tr[u].sum;
}else{
int mid = (tr[u].l + tr[u].r) >> 1, res = 0;
pushdown(u);
if(l <= mid) res += query(u<<1, l, r);
if(r > mid) res += query(u<<1|1, l, r);
return res;
}
}
struct Q{
// 记录操作的数组
int l, r, op;
}q[N];
bool 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 l = q[i].l, r = q[i].r;
int num = query(1, l, r);
if(q[i].op == 0){
update(1, r-num+1, r, 1);
update(1, l, r-num, 0);
} else{
update(1, l, l+num-1, 1);
update(1, l + num, r, 0);
}
}
return query(1, pos, pos);
}
int main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
//input();
cin>>n>>m;
for(int i = 1; i <= n; i++) cin>>a[i];
for(int i = 1; i <= m; i++){
cin>>q[i].op>>q[i].l>>q[i].r;
}
cin>>pos;
int l = 0, r = 1e5 + 10;
while(l < r){
int mid = (l + r + 1) >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout<<l<<endl;
return 0;
}