BZOJ 4552: [Tjoi2016&Heoi2016]排序

时间:2023-03-09 00:34:00
BZOJ 4552: [Tjoi2016&Heoi2016]排序

4552: [Tjoi2016&Heoi2016]排序

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

[Submit][Status][Discuss]

首先二分答案,然后需要知道进行m次排序后p位置上的数字是否大于mid。

对于一个mid,我们可以把序列里的数字分为两类,即大于mid的数和小于等于mid的数,分别用1和0表示。

对这些0和1进行排序时,对于一个区间[l,r]进行升序排序,等价于把所有的0放在前面,所有的1放在后面;降序排序反之。

用线段树支持区间求和及区间修改即可。

 #include <bits/stdc++.h>

 #define fread_siz 1024 

 inline int get_c(void)
{
static char buf[fread_siz];
static char *head = buf + fread_siz;
static char *tail = buf + fread_siz; if (head == tail)
fread(head = buf, , fread_siz, stdin); return *head++;
} inline int get_i(void)
{
register int ret = ;
register int neg = false;
register int bit = get_c(); for (; bit < ; bit = get_c())
if (bit == '-')neg ^= true; for (; bit > ; bit = get_c())
ret = ret * + bit - ; return neg ? -ret : ret;
} const int maxn = 1e5 + ; int n, m;
int total;
int num[maxn];
int map[maxn]; struct Query
{
int k, l, r;
}qry[maxn]; int pos; struct Node
{
int sum;
int tag;
int lt, rt;
}tree[maxn << ]; #define lson(t) (t << 1)
#define rson(r) (t << 1 | 1) void build(int t, int l, int r, int k)
{
tree[t].lt = l;
tree[t].rt = r;
tree[t].tag = -; if (l == r)
tree[t].sum = num[l] > k;
else
{
int mid = (l + r) >> ;
build(lson(t), l, mid, k);
build(rson(t), mid + , r, k);
tree[t].sum = tree[lson(t)].sum + tree[rson(t)].sum;
}
} void change(int t, int l, int r, int k)
{
if (l > r)return; if (l == tree[t].lt && r == tree[t].rt)
tree[t].sum = (r - l + ) * k, tree[t].tag = k;
else
{
int mid = (tree[t].lt + tree[t].rt) >> ; if (tree[t].tag != -)
{
change(lson(t), tree[t].lt, mid, tree[t].tag);
change(rson(t), mid + , tree[t].rt, tree[t].tag);
tree[t].tag = -;
} if (r <= mid)
change(lson(t), l, r, k);
else if (l > mid)
change(rson(t), l, r, k);
else
change(lson(t), l, mid, k), change(rson(t), mid + , r, k); tree[t].sum = tree[lson(t)].sum + tree[rson(t)].sum;
}
} int query(int t, int l, int r)
{
if (l == tree[t].lt && r == tree[t].rt)
return tree[t].sum; int mid = (tree[t].lt + tree[t].rt) >> ; if (tree[t].tag != -)
{
change(lson(t), tree[t].lt, mid, tree[t].tag);
change(rson(t), mid + , tree[t].rt, tree[t].tag);
tree[t].tag = -;
} if (r <= mid)
return query(lson(t), l, r);
else if (l > mid)
return query(rson(t), l, r);
else
return query(lson(t), l, mid) + query(rson(t), mid + , r);
} inline bool check(int mid)
{
build(, , n, mid); for (int i = ; i <= m; ++i)
{
int q = query(, qry[i].l, qry[i].r); if (qry[i].k)
{
change(, qry[i].l, qry[i].l + q - , );
change(, qry[i].l + q, qry[i].r, );
}
else
{
change(, qry[i].l, qry[i].r - q, );
change(, qry[i].r - q + , qry[i].r, );
}
} return query(, pos, pos);
} signed main(void)
{
n = get_i();
m = get_i(); for (int i = ; i <= n; ++i)
num[i] = get_i(); for (int i = ; i <= m; ++i)
{
qry[i].k = get_i();
qry[i].l = get_i();
qry[i].r = get_i();
} pos = get_i(); memcpy(map, num, sizeof(map));
std::sort(map + , map + + n);
total = std::unique(map + , map + + n) - map; int lt = , rt = total, mid, ans; while (lt <= rt)
{
if (check(mid = (lt + rt) >> ))
lt = mid + ;
else
rt = mid - , ans = mid;
} printf("%d\n", map[ans]);
}

@Author: YouSiki