4552: [Tjoi2016&Heoi2016]排序
Time Limit: 60 Sec Memory Limit: 256 MB
Submit: 1697 Solved: 883
[Submit][Status][Discuss]Description
在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q位置上的数字。Input
输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。1 <= n, m <= 10^5第二行为n个整数,表示1到n的一个全排列。接下来输入m行,每一行有三个整数op, l, r, op为0代表升序排序,op为1代表降序排序, l, r 表示排序的区间。最后输入一个整数q,q表示排序完之后询问的位置, 1 <= q <= n。1 <= n <= 10^5,1 <= m <= 10^5Output
输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。
Sample Input
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3Sample Output
5HINT
Source
整体难度不大,算是比较自然的思路,但是容易往离线排序等错误的方向思考,一旦知道了大致思路就好做了。
首先我们知道,对于一个01序列排序,用线段树维护的话可以做到单次排序复杂度仅为log级别。
这道题只有一个询问,所以离线没有意义,而一个询问让我们很自然的想到二分答案。先二分出这个位置上的数是多少,然后将所有小于等于的数全部赋为0,其余赋为1,这样每次排序都是01序列排序了。如果最后p位置上的数为0则说明最终答案小于等于当前二分的答案,反之亦然。
这样这个问题就在$O(n \log^2 n)$的复杂度内解决了。
1 #include<cstdio> 2 #include<algorithm> 3 #define ls (x<<1) 4 #define rs ((x<<1)|1) 5 #define lson ls,L,mid 6 #define rson rs,mid+1,R 7 #define rep(i,l,r) for (int i=l; i<=r; i++) 8 using namespace std; 9 10 const int N=100100; 11 int n,m,qry,a[N],c[N],sm[N<<2],tag[N<<2]; 12 struct P{ int op,l,r; }b[N]; 13 14 void push(int x,int L,int R){ 15 if (tag[x]==-1) return; 16 int mid=(L+R)>>1; 17 sm[ls]=(mid-L+1)*tag[x]; tag[ls]=tag[x]; 18 sm[rs]=(R-mid)*tag[x]; tag[rs]=tag[x]; 19 tag[x]=-1; 20 } 21 22 void build(int x,int L,int R){ 23 tag[x]=-1; 24 if (L==R) { sm[x]=c[L]; return; } 25 int mid=(L+R)>>1; 26 build(lson); build(rson); 27 sm[x]=sm[ls]+sm[rs]; 28 } 29 30 void mdf(int x,int L,int R,int l,int r,int k){ 31 if (L==l && r==R){ sm[x]=k*(R-L+1); tag[x]=k; return; } 32 int mid=(L+R)>>1; push(x,L,R); 33 if (r<=mid) mdf(lson,l,r,k); 34 else if (l>mid) mdf(rson,l,r,k); 35 else mdf(lson,l,mid,k),mdf(rson,mid+1,r,k); 36 sm[x]=sm[ls]+sm[rs]; 37 } 38 39 int que(int x,int L,int R,int l,int r){ 40 if (L==l && r==R) return sm[x]; 41 int mid=(L+R)>>1; push(x,L,R); 42 if (r<=mid) return que(lson,l,r); 43 else if (l>mid) return que(rson,l,r); 44 else return que(lson,l,mid)+que(rson,mid+1,r); 45 } 46 47 int main(){ 48 scanf("%d%d",&n,&m); 49 rep(i,1,n) scanf("%d",&a[i]); 50 rep(i,1,m) scanf("%d%d%d",&b[i].op,&b[i].l,&b[i].r); 51 scanf("%d",&qry); 52 int L=1,R=n; 53 while (L<R){ 54 int mid=(L+R)>>1; 55 rep(i,1,n) if (a[i]<=mid) c[i]=0; else c[i]=1; 56 build(1,1,n); 57 rep(i,1,m){ 58 int l=b[i].l,r=b[i].r,s=que(1,1,n,l,r); 59 if (b[i].op==0){ 60 if (l<=r-s) mdf(1,1,n,l,r-s,0); 61 if (r-s+1<=r) mdf(1,1,n,r-s+1,r,1); 62 }else{ 63 if (l<=l+s-1) mdf(1,1,n,l,l+s-1,1); 64 if (l+s<=r) mdf(1,1,n,l+s,r,0); 65 } 66 } 67 if (que(1,1,n,qry,qry)==0) R=mid; else L=mid+1; 68 } 69 printf("%d\n",L); 70 return 0; 71 }