【[HEOI2016/TJOI2016]排序】
阿新 • • 發佈:2019-01-01
巧妙思路題
有一個重要的思想就是把大於某一個數的數都變成\(1\),小於這個數的都變成\(0\),這個只有\(0\)和\(1\)的序列就很好處理了
由於我們只需要在最後求出一個位置上是什麼數就可以了,所以我們沒有必要去精確算出來這一位上是什麼數
顯然是可以二分的
我們二分出來一個答案,我們按照上述的方法處理序列,之後由於只有\(0\)和\(1\)了,我們可以直接用線段樹來完成排序
之後看看目標位置是\(0\)還是\(1\),可以得出當前這個答案是比真正的答案小還是大的判斷
程式碼
#include<iostream> #include<cstdio> #include<cstring> #define re register #define maxn 30005 inline int read() { char c=getchar(); int x=0; while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar(); return x; } int l[maxn<<2],r[maxn<<2],tag[maxn<<2],d[maxn<<2]; int a[maxn],n,m; int op[maxn],X[maxn],Y[maxn]; int q; void build(int x,int y,int i) { l[i]=x,r[i]=y; if(x==y) return; int mid=x+y>>1; build(x,mid,i<<1),build(mid+1,y,i<<1|1); } void Rebuild(int x,int y,int i,int val) { tag[i]=-1; if(x==y) { if(a[x]>val) d[i]=1; else d[i]=0; return; } int mid=x+y>>1; Rebuild(x,mid,i<<1,val),Rebuild(mid+1,y,i<<1|1,val); d[i]=d[i<<1]+d[i<<1|1]; } inline void pushdown(int i) { if(tag[i]==-1) return; tag[i<<1]=tag[i]; tag[i<<1|1]=tag[i]; d[i<<1]=(r[i<<1]-l[i<<1]+1)*tag[i]; d[i<<1|1]=(r[i<<1|1]-l[i<<1|1]+1)*tag[i]; tag[i]=-1; } void change(int x,int y,int val,int i) { if(x<=l[i]&&y>=r[i]) { d[i]=(r[i]-l[i]+1)*val; tag[i]=val; return; } pushdown(i); int mid=l[i]+r[i]>>1; if(y<=mid) change(x,y,val,i<<1); else if(x>mid) change(x,y,val,i<<1|1); else change(x,y,val,i<<1),change(x,y,val,i<<1|1); d[i]=d[i<<1]+d[i<<1|1]; } int query(int x,int y,int i) { if(x<=l[i]&&y>=r[i]) return d[i]; pushdown(i); int mid=l[i]+r[i]>>1; if(y<=mid) return query(x,y,i<<1); if(x>mid) return query(x,y,i<<1|1); return query(x,y,i<<1)+query(x,y,i<<1|1); } inline int check(int x) { Rebuild(1,n,1,x); for(re int i=1;i<=m;i++) { int t=query(X[i],Y[i],1); if(!t||t==Y[i]-X[i]+1) continue; if(!op[i]) change(X[i],Y[i]-t,0,1),change(Y[i]-t+1,Y[i],1,1); else change(X[i],X[i]+t-1,1,1),change(X[i]+t,Y[i],0,1); } return query(q,q,1); } int main() { n=read();m=read(); for(re int i=1;i<=n;i++) a[i]=read(); for(re int i=1;i<=m;i++) op[i]=read(),X[i]=read(),Y[i]=read(); build(1,n,1); q=read(); int l=1,r=n,ans; while(l<=r) { int mid=l+r>>1; if(!check(mid)) r=mid-1,ans=mid; else l=mid+1; } std::cout<<ans; return 0; }