P2824 [HEOI2016/TJOI2016] 排序
P2824 [HEOI2016/TJOI2016] 排序
题目描述
在 2016 年,佳媛姐姐喜欢上了数字序列。因而她经常研究关于序列的一些奇奇怪怪的问题,现在她在研究一个难题,需要你来帮助她。
这个难题是这样子的:给出一个 \(1\) 到 \(n\) 的排列,现在对这个排列序列进行 \(m\) 次局部排序,排序分为两种:
0 l r表示将区间 \([l,r]\) 的数字升序排序;1 l r表示将区间 \([l,r]\) 的数字降序排序。
注意,这里是对下标在区间 \([l,r]\) 内的数排序。
最后询问第 \(q\) 位置上的数字。
输入格式
输入数据的第一行为两个整数 \(n\) 和 \(m\),\(n\) 表示序列的长度,\(m\) 表示局部排序的次数。
第二行为 \(n\) 个整数,表示 \(1\) 到 \(n\) 的一个排列。
接下来输入 \(m\) 行,每一行有三个整数 \(\text{op},l,r\),\(\text{op}\) 为 \(0\) 代表升序排序,\(\text{op}\) 为 \(1\) 代表降序排序, \(l,r\) 表示排序的区间。
最后输入一个整数 \(q\),表示排序完之后询问的位置。
输出格式
输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第 \(q\) 位置上的数字。
输入输出样例 #1
输入 #1
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
输出 #1
5
说明/提示
河北省选 2016 第一天第二题。
对于 \(30\%\) 的数据,\(n,m\leq 1000\);
对于 \(100\%\) 的数据,\(n,m\leq 10^5\),\(1\leq q\leq n\)。
题意
非常清晰明了。
思路
非常巧妙的判断方法。
首先注意到求的只有一个位置的数,这是思考过程的关键点(也是题目难想的点)。深挖这个线索,可以得到:
-
我们不需要知道所有数的位置。
-
可以离线。
我们尝试把所有的精力放在 \(q\) 这一个位置上。比如说我们可以比较某个假设值 \(x\) 和 \(a_q\) 的大小。
同时,我们发现全部排序是昂贵的,同时依次遍历 \(m\) 次操作是必不可少的,因此我们必须要在短时间内处理每次操作的贡献。
综上,尝试二分答案。二分答案 \(x\),看真正的答案是否 \(\ge x\)。套路地,我们将 \(\ge x\) 的数赋值为 \(1\),其余为 \(-1\)。这时,所有 \(\ge x\) 的数等价,\(< x\) 的数等价。那么最终排序后,我们检查位置 \(q\)。如果是 \(1\),就说明 \(a_q\) 属于 \(\ge x\) 这个组里面的。正确性已在上述说明中体现了。
那么只剩最后一个问题了:如何快速处理 \(01\) 串的区间排序?这个简单,其实就是统计区间内 \(1\) 的个数,然后把所有 \(1\) 放后面。这就是一个区间求和,区间改的问题了,使用线段树解决。
这种 “降维思想”,通过降维获取高效率的检查,同时尝试二分等判断方式的方法,可以做到时间 \(\mathcal{O}(n) \to \mathcal{O}(\log ^ 2 n)\)。
代码
// Problem: P2824 [HEOI2016/TJOI2016] 排序
// Contest: Luogu
// Memory Limit: 256 MB
// Time Limit: 4000 ms
#include <bits/stdc++.h>
#define int long long
#define Misaka namespace
#define Network std
using Misaka Network;
const int N = 1e5 + 7;
int n, m, a[N], b[N], q, opt[N], L[N], R[N];
struct SGT{
int val[N << 2], lzy[N << 2];
#define ls (x << 1)
#define rs ((x << 1) | 1)
#define mid ((l + r) >> 1)
void build(int x, int l, int r){
lzy[x] = -1;
if(l == r) return val[x] = b[l], void();
build(ls, l, mid), build(rs, mid + 1, r);
val[x] = val[ls] + val[rs];
}
void pd(int x, int l, int r){
if(lzy[x] == -1) return;
lzy[ls] = lzy[x], lzy[rs] = lzy[x];
val[ls] = (mid - l + 1) * lzy[x];
val[rs] = (r - mid) * lzy[x];
lzy[x] = -1;
}
void Mdf(int x, int l, int r, int ql, int qr, int k){
if(qr < ql) return;
if(ql <= l && r <= qr){
val[x] = k * (r - l + 1);
lzy[x] = k; return;
}
pd(x, l, r);
if(ql <= mid) Mdf(ls, l, mid, ql, qr, k);
if(mid < qr) Mdf(rs, mid + 1, r, ql, qr, k);
val[x] = val[ls] + val[rs];
}
int Qur(int x, int l, int r, int ql, int qr){
if(ql <= l && r <= qr) return val[x];
pd(x, l, r); int res = 0;
if(ql <= mid) res += Qur(ls, l, mid, ql, qr);
if(mid < qr) res += Qur(rs, mid + 1, r, ql, qr);
return res;
}
void Sort(int opt, int l, int r){
int res = Qur(1, 1, n, l, r);
Mdf(1, 1, n, l, r, 0);
if(opt == 0) Mdf(1, 1, n, r - res + 1, r, 1);
else Mdf(1, 1, n, l, l + res - 1, 1);
}
} sgt;
bool check(int x){
for(int i = 1; i <= n; i ++){
b[i] = (a[i] >= x ? 1 : 0);
}
sgt.build(1, 1, n);
for(int i = 1; i <= m; i ++){
sgt.Sort(opt[i], L[i], R[i]);
}
return sgt.Qur(1, 1, n, q, q);
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= m; i ++){
cin >> opt[i] >> L[i] >> R[i];
}
cin >> q;
int l = 0, r = n + 1;
while(l + 1 < r){
int Mid = (l + r) >> 1;
if(check(Mid)) l = Mid;
else r = Mid;
}
cout << l << "\n";
return 0;
}
本文来自博客园,作者:Trent900,转载请注明原文链接:https://www.cnblogs.com/GE9X/p/21630115

浙公网安备 33010602011771号