*题解:P2824 [HEOI2016/TJOI2016] 排序
解析
“这个题不是典爆了,,,只跟大小相关的题想不到 0/1 Trick 建议先多做题。”
收到。
二分答案 \(x\),将大于等于 \(x\) 的数都标记为 \(1\),小于 \(x\) 的数都标记为 \(0\)。这样排序操作就变成了对 \(0/1\) 串排序,而这个操作相当于统计区间 \(1\) 个数和区间赋值,可以用线段树来维护。最终答案就为使得所有操作过后位置 \(q\) 上的数为 \(1\) 的最小 \(x\)。
时间复杂度 \(O(m\log^2n)\)。
代码
#include <bits/stdc++.h>
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 1e5 + 5,M = 2e5 + 5,mod = 998244353;
int a[N],b[N];
int cnt1[N << 2],tag[N << 2];
int pos;
struct Query{
int op,l,r;
}q[N];
int n,m;
void push_up(int p){
cnt1[p] = cnt1[ls(p)] + cnt1[rs(p)];
}
void build(int p,int l,int r){
tag[p] = -1;
if(l == r){
cnt1[p] = b[l];
return;
}
build(ls(p),l,mid),build(rs(p),mid + 1,r);
push_up(p);
}
void add_tag(int p,int l,int r,int k){
tag[p] = k;
cnt1[p] = (r - l + 1) * k;
}
void push_down(int p,int l,int r){
if(tag[p] == -1) return;
add_tag(ls(p),l,mid,tag[p]);
add_tag(rs(p),mid + 1,r,tag[p]);
tag[p] = -1;
}
void modi(int p,int l,int r,int L,int R,int k){
if(l > R || r < L) return;
if(l >= L && r <= R){
add_tag(p,l,r,k);
return;
}
push_down(p,l,r);
modi(ls(p),l,mid,L,R,k),modi(rs(p),mid + 1,r,L,R,k);
push_up(p);
}
int ask(int p,int l,int r,int L,int R){
if(l > R || r < L) return 0;
if(l >= L && r <= R){
return cnt1[p];
}
push_down(p,l,r);
return ask(ls(p),l,mid,L,R) + ask(rs(p),mid + 1,r,L,R);
}
bool chk(int x){
for(int i=1;i<=n;i++){
b[i] = a[i] >= x;
}
build(1,1,n);
for(int i=1;i<=m;i++){
int l = q[i].l,r = q[i].r;
int x = ask(1,1,n,l,r);
if(q[i].op == 0){
modi(1,1,n,l,r - x,0);
modi(1,1,n,r - x + 1,r,1);
}else{
modi(1,1,n,l,l + x - 1,1);
modi(1,1,n,l + x,r,0);
}
}
return ask(1,1,n,pos,pos);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
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 = 1,r = n;
while(l < r){
int md = (l + r + 1) >> 1;
if(chk(md)){
l = md;
}else{
r = md - 1;
}
}
cout<<l;
return 0;
}

浙公网安备 33010602011771号