[题解]luogu_P2824_HEOI2016排序(线段树/二分
很难想,首先要二分答案,这样对于所有大于mid的数可以当做1,所有小于mid的可以当做0,这些1或0内部怎么排其实无所谓,然后1全放一边就可以,单调性的话比较好说,因为p点的数要么比mid大要么小,排列答案只会有一个
#include<bits/stdc++.h> #define ls (x<<1) #define rs (x<<1|1) #define mid ((l+r)>>1) using namespace std; const int maxn=100009; int n,m,a[maxn],p,L[maxn],R[maxn],ch[maxn]; struct node{ int sum,tg; }t[maxn<<2]; inline void upd(int x){ t[x].sum=t[ls].sum+t[rs].sum; } inline void pd(int x,int l,int r){ if(t[x].tg){ t[ls].tg=t[x].tg; t[rs].tg=t[x].tg; if(t[x].tg==1){t[ls].sum=(mid-l+1);t[rs].sum=(r-mid);} else t[ls].sum=t[rs].sum=0; t[x].tg=0; } } void build(int x,int l,int r,int md){ if(l==r){ t[x].sum=(a[l]>=md);t[x].tg=0; return ; } build(ls,l,mid,md);build(rs,mid+1,r,md); upd(x);t[x].tg=0; } void change(int x,int l,int r,int L,int R,int val){ if(L<=l&&r<=R){ t[x].sum=val*(r-l+1); t[x].tg=val?1:-1; return; } pd(x,l,r); if(L<=mid)change(ls,l,mid,L,R,val); if(R>mid)change(rs,mid+1,r,L,R,val); upd(x); } int query(int x,int l,int r,int L,int R){ if(L<=l&&r<=R)return t[x].sum; pd(x,l,r); int ans=0; if(L<=mid)ans+=query(ls,l,mid,L,R); if(R>mid)ans+=query(rs,mid+1,r,L,R); return ans; } int queryp(int x,int l,int r,int pos){ if(l==r)return t[x].sum; pd(x,l,r); if(pos<=mid)return queryp(ls,l,mid,pos); else return queryp(rs,mid+1,r,pos); } bool check(int md){ build(1,1,n,md); for(int i=1;i<=m;i++){ int cnt1=query(1,1,n,L[i],R[i]); if(cnt1==0)continue; if(ch[i]==0){ change(1,1,n,R[i]-cnt1+1,R[i],1); change(1,1,n,L[i],R[i]-cnt1,0); } else{ change(1,1,n,L[i],L[i]+cnt1-1,1); change(1,1,n,L[i]+cnt1,R[i],0); } } return queryp(1,1,n,p); } int main(){ // freopen("4.in","r",stdin); 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",&ch[i],&L[i],&R[i]); scanf("%d",&p); int LL=1,RR=n,ans; while(LL<=RR){ int midd=(LL+RR)>>1; if(check(midd))ans=midd,LL=midd+1; else RR=midd-1; } printf("%d",ans); }