【BZOJ4552】【HEOI2016】排序 [二分答案][线段树]

排序

Time Limit: 60 Sec  Memory Limit: 256 MB
[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表示局部排序的次数。
  第二行为n个整数,表示1到n的一个全排列。
  接下来输入m行,每一行有三个整数op, l, r,
   op为0代表升序排序,op为1代表降序排序, l, r 表示排序的区间。
  最后输入一个整数q,q表示排序完之后询问的位置。

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

  1 <= n <= 10^5,1 <= m <= 10^5, 1 <= q <= n。

Solution

  我们先考虑如果权值很小的话怎么做,显然可以对每个权值开一个线段树维护在哪些位置出现过。

  那么排序显然就是覆盖连续的一段。只要知道某一区间有几个这个权值即可。

  但是这样显然是过不了的,于是我们考虑二分答案,把val >= mid的设为1,其余的设为0

  这样就把权值变成了0/1,那么显然我们按照以上操作,如果Q位置上是1说明mid<=Ans还可以更大一点否则说明mid>Ans

  只要支持区间求和以及区间覆盖0/1即可。

Code

  1 #include<iostream>
  2 #include<string>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cmath>
  8 using namespace std;
  9 typedef long long s64;
 10  
 11 const int ONE = 400005;
 12 const int MOD = 1e9 + 7;
 13  
 14 int get()
 15 {
 16         int res = 1, Q = 1; char c;
 17         while( (c = getchar()) < 48 || c > 57)
 18             if(c == '-') Q = -1;
 19         if(Q) res = c - 48;
 20         while( (c = getchar()) >= 48 && c <= 57)
 21             res = res * 10 + c - 48;
 22         return res * Q;
 23 }
 24  
 25 int n, m, Q;
 26 int a[ONE];
 27 int res, now;
 28  
 29 struct power
 30 {
 31         struct point
 32         {
 33             int val, tag;
 34         }Node[ONE];
 35  
 36         void Build(int i, int l, int r)
 37         {
 38             Node[i].tag = -1;
 39             if(l == r) return;
 40             int mid = l + r >> 1;
 41             Build(i << 1, l, mid);
 42             Build(i << 1 | 1, mid + 1, r);
 43         }
 44  
 45         int pushdown(int i, int l, int r)
 46         {
 47             int mid = l + r >> 1;
 48             if(Node[i].tag != -1)
 49             {
 50                 Node[i << 1].tag = Node[i].tag;
 51                 Node[i << 1].val = Node[i].tag * (mid - l + 1);
 52                 Node[i << 1 | 1].tag = Node[i].tag;
 53                 Node[i << 1 | 1].val = Node[i].tag * (r - (mid + 1) + 1);
 54                 Node[i].tag = -1;
 55             }
 56         }
 57  
 58         void Update(int i, int l, int r, int L, int R, int x)
 59         {
 60             if(L > R) return;
 61             if(L <= l && r <= R)
 62             {
 63                 Node[i].tag = x;
 64                 Node[i].val = x * (r - l + 1);
 65                 return;
 66             }
 67             pushdown(i, l, r);
 68             int mid = l + r >> 1;
 69             if(L <= mid) Update(i << 1, l, mid, L, R, x);
 70             if(mid + 1 <= R) Update(i << 1 | 1, mid + 1, r, L, R, x);
 71             Node[i].val = Node[i << 1].val + Node[i << 1 | 1].val;
 72         }
 73  
 74         void Query(int i, int l, int r, int L, int R)
 75         {
 76             if(L > R) return;
 77             if(L <= l && r <= R)
 78             {
 79                 res += Node[i].val;
 80                 return;
 81             }
 82             pushdown(i, l, r);
 83             int mid = l + r >> 1;
 84             if(L <= mid) Query(i << 1, l, mid, L, R);
 85             if(mid + 1 <= R) Query(i << 1 | 1, mid + 1, r, L, R);
 86         }
 87 }C[2];
 88  
 89 struct operate
 90 {
 91         int l, r, x;
 92 }oper[ONE];
 93  
 94 void Modify(int id, int Left, int Right)
 95 {
 96         res = 0;
 97         C[id].Query(1, 1, n, Left, Right);
 98         C[id].Update(1, 1, n, Left, Right, 0);
 99         C[id].Update(1, 1, n, now, now + res - 1, 1);
100         now += res;
101 }
102  
103 int Check(int mid)
104 {
105         for(int i = 0; i <= 1; i++)
106             C[i].Node[1].tag = 0;
107  
108         for(int i = 1; i <= n; i++)
109             C[a[i] >= mid].Update(1, 1, n, i, i, 1);
110  
111         for(int i = 1; i <= m; i++)
112         {
113             now = oper[i].l;
114             if(oper[i].x == 0) for(int id = 0; id <= 1; id++) Modify(id, oper[i].l, oper[i].r);
115             if(oper[i].x == 1) for(int id = 1; id >= 0; id--) Modify(id, oper[i].l, oper[i].r);
116         }
117  
118         res = 0, C[1].Query(1, 1, n, Q, Q);
119         return res;
120 }
121  
122 int main()
123 {
124         n = get();  m = get();
125         for(int i = 1; i <= n; i++)
126             a[i] = get();
127         for(int i = 1; i <= m; i++)
128             oper[i].x = get(), oper[i].l = get(), oper[i].r = get();
129  
130         Q = get();
131         int l = 1, r = n;
132         while(l < r - 1)
133         {
134             int mid = l + r >> 1;
135             if(Check(mid)) l = mid;
136             else r = mid;
137         }
138  
139         if(Check(r)) printf("%d", r);
140         else printf("%d", l);
141 }
142 
View Code

 

  

posted @ 2017-11-01 22:39  BearChild  阅读(251)  评论(0编辑  收藏  举报