[HEOI2016]排序
题目描述
在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。这个难题是这样子 的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2: (1,l,r)表示将区间[l,r]的数字降序排序最后询问第q位置上的数字。
输入输出格式
输入格式:输入数据的第一行为两个整数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^5
输出格式:输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。
输入输出样例
输入样例#1:
6 3 1 6 2 5 3 4 0 1 4 1 3 6 0 2 4 3
输出样例#1:
5
二分一个答案mid
然后用线段树维护每一位是否大于mid,大于为1,小于为0
最后如果第q位为1,那么说明答案大于mid
至于两个操作,可以简单的用线段树实现
对于1操作:
首先求出区间内1的数量cnt1,0的数量cnt2
按升序排序显然就是把所有1放到区间右边,0放左边
也就是update(l,l+cnt2-1,0),update(l+cnt2,r,1)
2操作类推
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 struct Node 7 { 8 int opt,l,r; 9 }ask[100001]; 10 int c[400001],lazy[400001],n,m,q,a[100001]; 11 void pushup(int rt) 12 { 13 c[rt]=c[rt*2]+c[rt*2+1]; 14 } 15 void build(int rt,int l,int r,int x) 16 { 17 if (l==r) 18 { 19 c[rt]=(a[l]>=x); 20 return; 21 } 22 int mid=(l+r)/2; 23 build(rt*2,l,mid,x); 24 build(rt*2+1,mid+1,r,x); 25 pushup(rt); 26 } 27 void pushdown(int rt,int l,int r,int mid) 28 { 29 if (lazy[rt]==0) 30 { 31 lazy[rt*2]=0; 32 lazy[rt*2+1]=0; 33 c[rt*2]=0; 34 c[rt*2+1]=0; 35 lazy[rt]=-1; 36 } 37 if (lazy[rt]==1) 38 { 39 lazy[rt*2]=1; 40 lazy[rt*2+1]=1; 41 c[rt*2]=mid-l+1; 42 c[rt*2+1]=r-mid; 43 lazy[rt]=-1; 44 } 45 } 46 void update(int rt,int l,int r,int L,int R,int d) 47 { 48 if (L>R) return ; 49 if (l>=L&&r<=R) 50 { 51 if (d==0) c[rt]=0,lazy[rt]=0; 52 else c[rt]=r-l+1,lazy[rt]=1; 53 return; 54 } 55 int mid=(l+r)/2; 56 pushdown(rt,l,r,mid); 57 if (L<=mid) update(rt*2,l,mid,L,R,d); 58 if (R>mid) update(rt*2+1,mid+1,r,L,R,d); 59 pushup(rt); 60 } 61 int query(int rt,int l,int r,int L,int R) 62 { 63 if (l>=L&&r<=R) 64 { 65 return c[rt]; 66 } 67 int mid=(l+r)/2; 68 pushdown(rt,l,r,mid); 69 int s=0; 70 if (L<=mid) s+=query(rt*2,l,mid,L,R); 71 if (R>mid) s+=query(rt*2+1,mid+1,r,L,R); 72 pushup(rt); 73 return s; 74 } 75 bool check(int mid) 76 {int i; 77 memset(c,0,sizeof(c)); 78 memset(lazy,-1,sizeof(lazy)); 79 build(1,1,n,mid); 80 for (i=1;i<=m;i++) 81 { 82 int l=ask[i].l,r=ask[i].r; 83 int cnt1=query(1,1,n,l,r); 84 int cnt2=r-l+1-cnt1; 85 if (ask[i].opt==0) 86 { 87 update(1,1,n,l,l+cnt2-1,0); 88 update(1,1,n,l+cnt2,r,1); 89 } 90 else 91 { 92 update(1,1,n,l,l+cnt1-1,1); 93 update(1,1,n,l+cnt1,r,0); 94 } 95 } 96 return query(1,1,n,q,q); 97 } 98 int main() 99 {int i; 100 cin>>n>>m; 101 for (i=1;i<=n;i++) 102 scanf("%d",&a[i]); 103 for (i=1;i<=m;i++) 104 scanf("%d%d%d",&ask[i].opt,&ask[i].l,&ask[i].r); 105 cin>>q; 106 int l=1,r=n,ans; 107 while (l<=r) 108 { 109 int mid=(l+r)/2; 110 if (check(mid)) ans=mid,l=mid+1; 111 else r=mid-1; 112 } 113 cout<<ans; 114 }