[HEOI2016/TJOI2016] 排序 题解
这题其实就是一个 thick 题,知道这个 thick 其实就是大水体了。
像这样的区间排序题,直接排序肯定不行,但是我们发现 01 数组排序很快,可以用线段树来实现 \(O(\log n)\) 的排序时间复杂度,就是区间赋值。
对大于等于这个值的都赋值为 1,其他为 0,若最后 \(a_q=1\) 就是可行的。
发现答案有单调性,直接二分即可。
#include<bits/stdc++.h>
#pragma GCC optimize(3)
#pragma GCC optimize("inline")
#pragma GCC target("avx", "sse2")
#pragma GCC optimize("unroll-loops")
using namespace std;
const int N=1e5+5;
int n,m,a[N];
int l[N],r[N],opt[N],X;
struct SEG {
#define ls p<<1
#define rs p<<1|1
int c[N<<2],tag[N<<2],len[N<<2];
void pushup(int p) {
c[p]=c[ls]+c[rs];
}
void pushdown(int p) {
if(tag[p]!=-1) {
tag[ls]=tag[p];
tag[rs]=tag[p];
c[ls]= tag[p]*len[ls];
c[rs]= tag[p]*len[rs];
tag[p]=-1;
}
}
void build(int p,int l,int r,int &x) {
tag[p]=-1;
len[p]=r-l+1;
if(l==r)return void (c[p]=(a[l]>=x));
int mid=l+r>>1;
build(ls,l,mid,x),build(rs,mid+1,r,x);
pushup(p);
}
void change(int p,int l,int r,int L,int R,int x) {
if(L<=l&&r<=R) {
c[p]=x*len[p];
tag[p]=x;
return ;
}
int mid=l+r>>1;
pushdown(p);
if(L<=mid)change(ls,l,mid,L,R,x);
if(R> mid)change(rs,mid+1,r,L,R,x);
pushup(p);
}
int query(int p,int l,int r,int L,int R) {
if(L<=l&&r<=R) return c[p];
int mid=l+r>>1,res=0;
pushdown(p);
if(L<=mid) res+=query(ls,l,mid,L,R);
if(R> mid) res+=query(rs,mid+1,r,L,R);
return res;
}
} seg;
bool check(int mid) {
seg.build(1,1,n,mid);
//cout<<mid<<endl<<endl;
for(int i=1; i<=m; i++) {
int x=seg.query(1,1,n,l[i],r[i]);
if(x==r[i]-l[i]+1 ||!x)continue;
//cout<<x<<" "<<opt[i]<<endl;
if(opt[i]) {
seg.change(1,1,n,l[i],l[i]+x-1,1);
seg.change(1,1,n,l[i]+x,r[i],0);
}
else {
seg.change(1,1,n,l[i],(r[i]-x),0);
seg.change(1,1,n,(r[i]-x)+1,r[i],1);
}
}
//cout<<seg.query(1,1,n,X,X)<<endl;
return seg.query(1,1,n,X,X);
}
signed 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",&opt[i],&l[i],&r[i]);
int l=1,r=n,ans=0;
scanf("%d",&X);
while(l<=r) {
int mid=l+r>>1;
if(check(mid))
ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d",ans);
return 0;
}

浙公网安备 33010602011771号