BZOJ4552:[TJOI2016&HEOI2016]排序(线段树,二分)
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^5
Output
输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。
Sample Input
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
Sample Output
5
Solution
也就只有刷刷水才能挽救一下博客文章数量这样子
二分最终的答案是不是小于等于$mid$,然后把小于等于$mid$的置为$0$,大于的置为$1$。
然后区间$sort$就可以查询一下区间$1$的个数然后用线段树区间覆盖来搞。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (100009) 5 using namespace std; 6 7 struct Edge{int val,down;}Segt[N<<2]; 8 int n,m,p,a[N],opt[N],l[N],r[N]; 9 10 void Pushdown(int now,int l,int r) 11 { 12 if (Segt[now].down!=-1) 13 { 14 int mid=(l+r)>>1; 15 Segt[now<<1].down=Segt[now<<1|1].down=Segt[now].down; 16 Segt[now<<1].val=(mid-l+1)*Segt[now].down; 17 Segt[now<<1|1].val=(r-mid)*Segt[now].down; 18 Segt[now].down=-1; 19 } 20 } 21 22 void Update(int now,int l,int r,int l1,int r1,int k) 23 { 24 if (l>r1 || r<l1) return; 25 if (l1<=l && r<=r1) 26 { 27 Segt[now].val=(r-l+1)*k; 28 Segt[now].down=k; 29 return; 30 } 31 Pushdown(now,l,r); 32 int mid=(l+r)>>1; 33 Update(now<<1,l,mid,l1,r1,k); 34 Update(now<<1|1,mid+1,r,l1,r1,k); 35 Segt[now].val=Segt[now<<1].val+Segt[now<<1|1].val; 36 } 37 38 int Query(int now,int l,int r,int l1,int r1) 39 { 40 if (l>r1 || r<l1) return 0; 41 if (l1<=l && r<=r1) return Segt[now].val; 42 Pushdown(now,l,r); 43 int mid=(l+r)>>1; 44 return Query(now<<1,l,mid,l1,r1)+Query(now<<1|1,mid+1,r,l1,r1); 45 } 46 47 bool check(int x) 48 { 49 for (int i=1; i<=n*4; ++i) Segt[i].val=0, Segt[i].down=-1; 50 for (int i=1; i<=n; ++i) 51 Update(1,1,n,i,i,a[i]>x); 52 for (int i=1; i<=m; ++i) 53 { 54 int sum=Query(1,1,n,l[i],r[i]); 55 if (opt[i]==0) Update(1,1,n,r[i]-sum+1,r[i],1), Update(1,1,n,l[i],r[i]-sum,0); 56 else Update(1,1,n,l[i],l[i]+sum-1,1), Update(1,1,n,l[i]+sum,r[i],0); 57 } 58 return !Query(1,1,n,p,p); 59 } 60 61 int main() 62 { 63 scanf("%d%d",&n,&m); 64 for (int i=1; i<=n; ++i) 65 scanf("%d",&a[i]); 66 for (int i=1; i<=m; ++i) 67 scanf("%d%d%d",&opt[i],&l[i],&r[i]); 68 scanf("%d",&p); 69 int l=1,r=n,ans=-1; 70 while (l<=r) 71 { 72 int mid=(l+r)>>1; 73 if (check(mid)) r=mid-1,ans=mid; 74 else l=mid+1; 75 } 76 printf("%d\n",ans); 77 }