题目大意
给出长度为n的序列,有m个排序操作,对一个区间升序或降序排序,求操作完某一位的值。
题解
一个非常不显然的性质,本题满足二分性质。二分一个答案,如果原数大于或等于答案就标记为1,不然标记为0。排序完可以知道目标位到底是大于等于还是小于答案,适当调整答案即可。
code
using namespace std;
int const maxn=100000;
int n,m,q,a[maxn+10],l[maxn+10],r[maxn+10],op[maxn+10],ans[maxn*50+10],flag[maxn*50+10];
void change(int now,int l,int r,int l1,int r1,int val){
if(l1>r1)return;
int m=(l+r)/2;
if((flag[now]!=-1)&&(l!=r)){
ans[now*2]=(m-l+1)*flag[now];
ans[now*2+1]=(r-m)*flag[now];
flag[now*2]=flag[now*2+1]=flag[now];
flag[now]=-1;
}
if((l==l1)&&(r==r1)){
ans[now]=(r-l+1)*val;
flag[now]=val;
return;
}else if(r1<=m)change(now*2,l,m,l1,r1,val);
else if(m*2+1,m+1,r,l1,r1,val);
else{
change(now*2,l,m,l1,m,val);
change(now*2+1,m+1,r,m+1,r1,val);
}
ans[now]=ans[now*2]+ans[now*2+1];
}
int ask(int now,int l,int r,int l1,int r1){
if(l1>r1)return 0;
int m=(l+r)/2;
if((flag[now]!=-1)&&(l!=r)){
ans[now*2]=(m-l+1)*flag[now];
ans[now*2+1]=(r-m)*flag[now];
flag[now*2]=flag[now*2+1]=flag[now];
flag[now]=-1;
}
if((l==l1)&&(r==r1))return ans[now];
else if(r1<=m)return ask(now*2,l,m,l1,r1);
else if(mreturn ask(now*2+1,m+1,r,l1,r1);
else return ask(now*2,l,m,l1,m)+ask(now*2+1,m+1,r,m+1,r1);
}
int main(){
//freopen("len.in","r",stdin);
//freopen("len.out","w",stdout);
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n)scanf("%d",&a[i]);
fo(i,1,m)
scanf("%d%d%d",&op[i],&l[i],&r[i]);
scanf("%d",&q);
int le=1,ri=n;
memset(flag,255,sizeof(flag));
while(le!=ri){
int mid=(le+ri+1)/2;
fo(i,1,n)
change(1,1,n,i,i,a[i]>=mid);
fo(i,1,m){
int tmp=ask(1,1,n,l[i],r[i]);
if(op[i]){
change(1,1,n,l[i],l[i]+tmp-1,1);
change(1,1,n,l[i]+tmp,r[i],0);
}else{
change(1,1,n,l[i],r[i]-tmp,0);
change(1,1,n,r[i]-tmp+1,r[i],1);
}
}
if(ask(1,1,n,q,q))le=mid;
else ri=mid-1;
}
printf("%d",le);
return 0;
}