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

4552: [Tjoi2016&Heoi2016]排序

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 1451  Solved: 734
[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

Analysis

这道题的正解思路简直清新qwq

第一眼过去肯定就是拿线段树合并分裂强行模拟

但是正解:元素模糊化+二分

(元素模糊化是我定义出来的,,,= =)

首先这道题拿正常线段树做的最大难点非常显然:这个要怎么排序啊

所以根据正解思路,我们将元素模糊处理成0和1,这样排序就变成了 统计+区间赋值

怎么模糊化呢?二分答案 line ,然后对于 ≥line 的设置成 1,否则为 0

这样,把二分需要用到的 check函数 定义为第 q 个元素的 0/1 状态

那么根据我们的定义,这一位肯定是要 ≥line 的(否则就不对劲),以此确定下一步的二分范围

有点反证法的意味啊,,,

Code

  1 #include<cstdio>
  2 #include<iostream>
  3 #define maxn 1000000
  4 #define mid (L+R)/2
  5 #define lc (rt<<1)
  6 #define rc (rt<<1|1)
  7 using namespace std;
  8
  9 int arr[maxn],line,n,m,qwq;
 10
 11 struct data{ int op,L,R; }ask[maxn];
 12
 13 struct node{
 14     int sum,lazy;
 15 }T[maxn*4];
 16
 17 void maintain(int rt){ T[rt].sum = T[lc].sum+T[rc].sum; }
 18
 19 void pushdown(int rt,int L,int R){
 20     if(!T[rt].lazy) return;
 21
 22     T[lc].sum = (T[rt].lazy-1)*(mid-L+1);
 23     T[rc].sum = (T[rt].lazy-1)*(R-mid);
 24     T[lc].lazy = T[rc].lazy = T[rt].lazy;
 25     T[rt].lazy = 0;
 26 }
 27
 28 void build(int rt,int L,int R){
 29     T[rt].sum = T[rt].lazy = 0;
 30     if(L == R) T[rt].sum = (arr[L]>=line?1:0);
 31     else{
 32         build(lc,L,mid); build(rc,mid+1,R);
 33         maintain(rt);
 34     }
 35 }
 36
 37 int query(int rt,int L,int R,int qL,int qR){
 38     pushdown(rt,L,R);
 39     if(qL <= L && R <= qR) return T[rt].sum;
 40     else{
 41         int ans = 0;
 42         if(qL <= mid) ans += query(lc,L,mid,qL,qR);
 43         if(qR > mid) ans += query(rc,mid+1,R,qL,qR);
 44         return ans;
 45     }
 46 }
 47
 48 int query(int rt,int L,int R,int pos){
 49     pushdown(rt,L,R);
 50 //    if(pos < L || R < pos) return -1;
 51     if(L == R) return T[rt].sum;
 52     else{
 53         if(pos <= mid) return query(lc,L,mid,pos);
 54         else return query(rc,mid+1,R,pos);
 55     }
 56 }
 57
 58 void modify(int rt,int L,int R,int qL,int qR,int val){
 59     pushdown(rt,L,R);
 60     if(qL > qR) return;
 61     if(qL <= L && R <= qR){
 62         T[rt].sum = val*(R-L+1); T[rt].lazy = val+1;
 63     }else{
 64         if(qL <= mid) modify(lc,L,mid,qL,qR,val);
 65         if(qR > mid) modify(rc,mid+1,R,qL,qR,val);
 66         maintain(rt);
 67     }
 68 }
 69
 70 void SORT(int op,int L,int R){
 71     int sum = query(1,1,n,L,R);
 72 //    printf("#%d: sum%d\n",op,sum);
 73     if(op){
 74         modify(1,1,n,L,L+sum-1,1);
 75         modify(1,1,n,L+sum,R,0);
 76     }else{
 77         modify(1,1,n,L,R-sum,0);
 78         modify(1,1,n,R-sum+1,R,1);
 79     }
 80 }
 81
 82 bool check(){
 83     build(1,1,n);
 84 //    cout << "Now...."; for(int i = 1;i <= n;i++) printf("%d ",query(1,1,n,i)); cout << endl;
 85     for(int i = 1;i <= m;i++){
 86         SORT(ask[i].op,ask[i].L,ask[i].R);
 87 //        printf("#%d Now..",i); for(int j = 1;j <= n;j++) printf("%d ",query(1,1,n,j)); cout << endl;
 88     }
 89     return query(1,1,n,qwq);
 90 }
 91
 92 int main(){
 93     scanf("%d%d",&n,&m);
 94
 95     for(int i = 1;i <= n;i++) scanf("%d",&arr[i]);
 96     for(int i = 1;i <= m;i++) scanf("%d%d%d",&ask[i].op,&ask[i].L,&ask[i].R);
 97
 98     scanf("%d",&qwq);
 99
100     int L = 1,R = n;
101     while(L < R){
102         line = (L+R+1)/2;
103         if(!check()) R = line-1;
104         else L = line;
105 //        printf("[%d,%d]: line%d --=",L,R,line);
106 //        for(int i = 1;i <= n;i++) printf("%d ",query(1,1,n,i)); cout << endl;
107     }
108
109     cout << R;
110
111     return 0;
112 }

线段树+二分

时间: 2024-10-20 18:27:02

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

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

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 二分答案,把 >= mid 的设成1.< mid 的设成0,之后排序就变成区间赋值了. #include<cstdio> #include<cstring> #include<algorithm> #define ls Ls[cr] #define rs Rs[cr] using namespace std; const int N=1e5+5,

bzoj4552 [Tjoi2016&amp;Heoi2016]排序 (线段树+二分)

题意:一个1~n的排列,m个操作: 0 x y:将ax~ay按升序排列: 1 x y:将ax~ay按降序排列. 询问m次操作后第aq的值. 输入:第一行:两个正整数n,m,表示序列的长度与询问的个数: 第二行:一个1~n的排列: 第3~m+2行:每行一个操作. 第m+3行:一个数q表示询问的位置. 输出:一个数表示aq的值. 样例输入: 6 3 1 6 2 5 3 4 0 1 4 1 3 6 0 2 4 3 样例输出: 5 解析:考虑二分答案,将小于答案的数变为0,将大于等于答案的变为1,这样整

bzoj 4552: [Tjoi2016&amp;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^

4552: [Tjoi2016&amp;Heoi2016]排序

4552: [Tjoi2016&Heoi2016]排序 Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q 位置上的数字. Input 输入数据的第一行为两个整数n和m.n表示序列的长度,

BZOJ 2527 Poi2011 Meteors 整体二分+线段树 / 可持久化线段树(MLE)

题目大意:给定一个环,每个节点有一个所属国家,k次事件,每次对[l,r]区间上的每个点点权加上一个值,求每个国家最早多少次操作之后所有点的点权和能达到一个值 首先我们考虑暴力想法 对于每个国家分开讨论 二分操作次数 但是这样每次Judge的时候我们要模拟1~mid所有的操作 浪费在这里的复杂度实在太大 这样做每个国家需要模拟O(klogk)次操作 时间复杂度O(nklogk) TLE 我们需要对浪费在这里的复杂度做一些改进 1.可持久化线段树(MLE) 每次二分一个mid之后 我们要找到mid次

[HEOI2016&amp;TJOI2016] 排序(线段树)

4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 2703  Solved: 1386[Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,

【BZOJ4552】排序(线段树,二分答案)

[BZOJ4552]排序(线段树,二分答案) 题面 BZOJ 题解 好神的题啊 直接排序我们做不到 怎么维护? 考虑一下,如果我们随便假设一个答案 怎么检验它是否成立? 把这个数设成\(1\),其他的数字都设成\(0\) 最后检查一下这个位置是不是\(1\)就好啦 但是这样没法排序 那么,我们考虑二分一个答案, 把所有比\(mid\)大的数都设成\(1\) 这样,如果在第\(Q\)位上的数字是\(1\) 意味着有一个不小于当前\(mid\)的数在这个位置上 否则就是一个比\(mid\)小的数在这

【BZOJ-3110】K大数查询 整体二分 + 线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6265  Solved: 2060[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

bzoj 1594: [Usaco2008 Jan]猜数游戏——二分+线段树

Description 为了提高自己低得可怜的智商,奶牛们设计了一个新的猜数游戏,来锻炼她们的逻辑推理能力. 游戏开始前,一头指定的奶牛会在牛棚后面摆N(1 <= N<= 1,000,000)堆干草,每堆有若干捆,并且没有哪两堆中的草一样多.所有草堆排成一条直线,从左到右依次按1..N编号,每堆中草的捆数在1..1,000,000,000之间. 然后,游戏开始.另一头参与游戏的奶牛会问那头摆干草的奶牛 Q(1 <= Q <= 25,000)个问题,问题的格式如下: 编号为Ql..Q