在2016年,佳媛姐姐喜歡上了數字序列。於是他常常研究關於序列的一些奇奇怪怪的問題,如今他在研究一個難題
,須要你來幫助他。這個難題是這樣子的:給出一個1到n的全排列,如今對這個全排列序列進行m次局部排序,排
序分爲兩種:1:(0,l,r)表示將區間[l,r]的數字升序排序2:(1,l,r)表示將區間[l,r]的數字降序排序最後詢問第q
位置上的數字。
輸出數據僅有一行,一個整數,表示按照順序將所有的部分排序結束後第q位置上的數字。ios
/* 題解很神奇。 二分答案k,那麼就是要判斷a[p]與k的大小關係。 咱們把序列變成0/1序列,0表明該位置的數小於k,1表明大於等於k,對於升降序操做, 用線段樹維護就能夠了,最後判斷一下。 */ #include<iostream> #include<cstdio> #include<cstring> #define N 30010 using namespace std; int a[N],b[N][3],n,m,p; int sum[N*4],tag[N*4]; void push_up(int k){ sum[k]=sum[k*2]+sum[k*2+1]; } void push_down(int k,int l,int r){ if(tag[k]==-1) return; int mid=l+r>>1; tag[k*2]=tag[k*2+1]=tag[k]; sum[k*2]=(mid-l+1)*tag[k]; sum[k*2+1]=(r-mid)*tag[k]; tag[k]=-1; } void change(int k,int l,int r,int x,int y,int val){ if(x>y) return; if(l>=x&&r<=y){ sum[k]=(r-l+1)*val; tag[k]=val; return; } push_down(k,l,r); int mid=l+r>>1; if(x<=mid) change(k*2,l,mid,x,y,val); if(y>mid) change(k*2+1,mid+1,r,x,y,val); push_up(k); } int query(int k,int l,int r,int x,int y){ if(l>=x&&r<=y) return sum[k]; push_down(k,l,r); int mid=l+r>>1,tot=0; if(x<=mid) tot+=query(k*2,l,mid,x,y); if(y>mid) tot+=query(k*2+1,mid+1,r,x,y); return tot; } bool check(int mid){ memset(tag,-1,sizeof(tag)); memset(sum,0,sizeof(sum)); for(int i=1;i<=n;i++) change(1,1,n,i,i,a[i]>=mid); for(int i=1;i<=m;i++){ int t=query(1,1,n,b[i][1],b[i][2]); if(!b[i][0]){ change(1,1,n,b[i][1],b[i][2]-t,0); change(1,1,n,b[i][2]-t+1,b[i][2],1); } else { change(1,1,n,b[i][1],b[i][1]+t-1,1); change(1,1,n,b[i][1]+t,b[i][2],0); } } int t=query(1,1,n,p,p); return t; } 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",&b[i][0],&b[i][1],&b[i][2]); scanf("%d",&p); int l=0,r=n,ans; while(l<=r){ int mid=l+r>>1; if(check(mid)) l=mid+1,ans=mid; else r=mid-1; } printf("%d",ans); return 0; }