[HEOI2016/TJOI2016]排序
题目描述
在 2016 2016 2016 年,佳媛姐姐喜欢上了数字序列。因而她经常研究关于序列的一些奇奇怪怪的问题,现在她在研究一个难题,需要你来帮助她。
这个难题是这样子的:给出一个 1 1 1 到 n n n 的排列,现在对这个排列序列进行 m m m 次局部排序,排序分为两种:
0 l r
表示将区间 [ l , r ] [l,r] [l,r] 的数字升序排序1 l r
表示将区间 [ l , r ] [l,r] [l,r] 的数字降序排序
注意,这里是对下标在区间
[
l
,
r
]
[l,r]
[l,r] 内的数排序。
最后询问第
q
q
q 位置上的数字。
输入格式
输入数据的第一行为两个整数 n n n 和 m m m, n n n 表示序列的长度, m m m 表示局部排序的次数。
第二行为 n n n 个整数,表示 1 1 1 到 n n n 的一个排列。
接下来输入 m m m 行,每一行有三个整数 op , l , r \text{op},l,r op,l,r, op \text{op} op 为 0 0 0 代表升序排序, op \text{op} op 为 1 1 1 代表降序排序, l , r l,r l,r 表示排序的区间。
最后输入一个整数 q q q,表示排序完之后询问的位置
输出格式
输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第 q 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 % 30\% 30% 的数据, n , m ≤ 1000 n,m\leq 1000 n,m≤1000
对于 100 % 100\% 100% 的数据, n , m ≤ 1 0 5 n,m\leq 10^5 n,m≤105, 1 ≤ q ≤ n 1\leq q\leq n 1≤q≤n
这个题显然是让我们写一种数据结构来维护区间排序,巨佬们可以用线段树分裂直接过,本蒟蒻也不会拿线段树分裂写,因此我就讲一种用普通的线段树的做法。
首先,我们考虑这个时间复杂度的瓶颈就是这个排序操作,如果用正常的排序的话,每次的复杂度都是 O ( n l o g n ) O(n logn) O(nlogn) ,这个复杂度显然对于这道题的数据范围是不可以接受的。
那么这道题妙的地方就要来了!!!既然这个排序不够高效,我们就让它变得高效。 众所周知,线段树维护 01 串的时间复杂度是
O
(
l
o
g
n
)
O(logn)
O(logn)。那么聪明的同学看到这就差不多把这道题切掉了。那么像我这样的蒟蒻还是一脸疑惑,这怎么变成 01 串的问题呢???
我们可以先假设经过所有操作后的第 p o s pos pos 个位置的数的值为 k k k ,我们可以将整个序列中大于 k k k 变成是1,小于 k k k 的数变成0。然后就挨个进行排序,(现在先不讲排序,下面会讲),最后如果第 p o s pos pos 个数为0,那么就证明 k k k 小了。因此我们可以二分一下 k k k,根据每次的 p o s pos pos 的值缩小边界即可。
最后再说一下排序,其实非常简单,就是因为是01串,那么我们只用维护一些区间内的1的数量,然后升序就将1全放在区间的右边。这个操作可以用区间修改就可以实现。
下面是代码实现
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch > '9' || ch < '0')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return x * f;
}
inline void write(int x)
{
if (x < 0)
{
x = -x;
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
const int N = 1e6 + 10;
int n, m;
int ask, L, R;
int w[N], ans;
struct Tag
{
int col;
bool flag;
};
struct question
{
int op, l, r;
} q[N];
struct Segmen_Tree
{
struct Tree
{
int l, r, val;
Tag tag;
} tr[N << 1];
inline void pushup(int u)
{
tr[u].val = tr[u << 1].val + tr[u << 1 | 1].val;
}
inline void build(int u, int l, int r, int pos)
{
tr[u].tag.flag = false;
tr[u].l = l, tr[u].r = r;
if (l == r)
{
tr[u].val = (w[l] >= pos);
return;
}
int mid = l + r >> 1;
build(u << 1, l, mid, pos), build(u << 1 | 1, mid + 1, r, pos);
pushup(u);
}
inline void pushdown(int u)
{
if (tr[u].tag.flag)
{
tr[u << 1].val = (tr[u << 1].r - tr[u << 1].l + 1) * tr[u].tag.col;
tr[u << 1 | 1].val = (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1) * tr[u].tag.col;
tr[u << 1].tag.flag = tr[u << 1 | 1].tag.flag = true;
tr[u << 1].tag.col = tr[u << 1 | 1].tag.col = tr[u].tag.col;
tr[u].tag.flag = false;
}
}
inline void modify(int u, int l, int r, int k)
{
if (l <= tr[u].l && r >= tr[u].r)
{
tr[u].val = (tr[u].r - tr[u].l + 1) * k;
tr[u].tag.flag = true;
tr[u].tag.col = k;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid)
modify(u << 1, l, r, k);
if (r > mid)
modify(u << 1 | 1, l, r, k);
pushup(u);
}
inline int query(int u, int l, int r)
{
if (l <= tr[u].l && r >= tr[u].r)
return tr[u].val;
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1, res = 0;
if (l <= mid)
res += query(u << 1, l, r);
if (r > mid)
res += query(u << 1 | 1, l, r);
return res;
}
inline bool check(int x)
{
build(1, 1, n, x);
int sum;
for (register int i = 1; i <= m; i++)
{
sum = query(1, q[i].l, q[i].r);
if (q[i].op)
{
modify(1, q[i].l, q[i].l + sum - 1, 1);
modify(1, q[i].l + sum, q[i].r, 0);
}
else
{
sum = q[i].r - q[i].l + 1 - sum;
modify(1, q[i].l, q[i].l + sum - 1, 0);
modify(1, q[i].l + sum, q[i].r, 1);
}
}
return query(1, ask, ask);
}
} god;
int main()
{
n = read();
m = read();
for (register int i = 1; i <= n; i++)
w[i] = read();
for (register int i = 1; i <= m; i++)
q[i].op = read(), q[i].l = read(), q[i].r = read();
ask = read();
L = 1, R = n;
while (L <= R)
{
int mid = L + R >> 1;
// cout<<mid<<endl;
if (god.check(mid))
ans = mid, L = mid + 1;
else
R = mid - 1;
}
write(ans);
return 0;
}
完结 ★,°:.☆( ̄▽ ̄)/$:.°★ 。