# 【TJOI2016】【bzoj4552】排序（二分答案+线段树01排序）

#### problem

1:(0,l,r)表示将区间[l,r]的数字升序排序
2:(1,l,r)表示将区间[l,r]的数字降序排序

#### solution

1.将所有 >= mid 的数变成 1, < mid 的数变成 0 （01排序不影响排序结果，得到相对的大小关系）
2.将处理过后的序列进行排序

change(r - sum + 1, r, 1); change(l, r - sum, 0);

#### codes

#include<cstdio>

const int maxn = 100010;

#define lch o<<1
#define rch o<<1|1
int _a[maxn], sgt[maxn<<2], tag[maxn<<2];
void build(int o, int l, int r){
tag[o] = -1;
if(l == r){
sgt[o] = _a[l];
return ;
}
int mid = l+r>>1;
build(lch,l,mid); build(rch,mid+1,r);
sgt[o] = sgt[lch]+sgt[rch];
}
int pushdown(int o, int l, int r){
if(tag[o] != -1){
int mid = l+r>>1;
sgt[lch] = (mid-l+1)*tag[o];
sgt[rch] = (r-mid)*tag[o];
tag[lch] = tag[rch] = tag[o];
tag[o] = -1;
}
}
int query(int o, int l, int r, int L, int R){
if(r < L || l > R)return 0;
if(L <= l && r <= R)return sgt[o];
pushdown(o, l, r);
int mid = l+r>>1, ans = 0;
if(L <= mid)ans += query(lch, l, mid, L, R);
if(R > mid)ans += query(rch, mid+1, r, L, R);
return ans;
}
void change(int o, int l, int r, int L, int R, int v){
if(r < L || l > R)return ;
if(L <= l && r <= R){
sgt[o] = (r-l+1)*v; tag[o] = v;
return ;
}
pushdown(o,l,r);
int mid = l+r>>1;
if(L <= mid)change(lch, l, mid, L, R, v);
if(R > mid)change(rch, mid+1, r, L, R, v);
sgt[o] = sgt[lch]+sgt[rch];
}

int n, m, a[maxn], op[maxn], x[maxn], y[maxn], pos;
int check(int _x){
for(int i = 1; i <= n; i++)
_a[i] = a[i]>=_x;
build(1,1,n);
for(int i = 1; i <= m; i++){
int t = query(1,1,n,x[i],y[i]);
if(op[i])change(1,1,n,x[i],x[i]+t-1,1),change(1,1,n,x[i]+t,y[i],0);
else change(1,1,n,x[i],y[i]-t,0), change(1,1,n,y[i]-t+1,y[i],1);
}
return query(1,1,n,pos,pos);
}

int main(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)scanf("%d",&a[i]);
for(int i = 1; i <= m; i++)scanf("%d%d%d",&op[i],&x[i],&y[i]);
scanf("%d", &pos);
int l = 1, r = n;
while(l < r){
int mid = l+r+1>>1;
if(check(mid))l = mid;
else r = mid-1;
}
printf("%d\n", l);
return 0;
}
posted @ 2018-05-18 06:09  gwj1139177410  阅读(125)  评论(0编辑  收藏  举报
 选择 第七项 第六项 第一项 第二项 第三项 第四项