[BZOJ4552][TJOI2016&&HEOI2016]排序

Posted HocRiser

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ4552][TJOI2016&&HEOI2016]排序相关的知识,希望对你有一定的参考价值。

 

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^5

Output

 输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。

Sample Input

6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3

Sample Output

5

HINT

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 }

 

以上是关于[BZOJ4552][TJOI2016&&HEOI2016]排序的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ4552][TJOI2016&&HEOI2016]排序

BZOJ4552:[Tjoi2016&Heoi2016]排序

[BZOJ] 4552: [Tjoi2016&Heoi2016]排序 #二分+线段树+算法设计策略

bzoj 4552 [Tjoi2016&Heoi2016]排序——二分答案

bzoj千题计划128:bzoj4552: [Tjoi2016&Heoi2016]排序

Bzoj4552: [Tjoi2016&Heoi2016]排序