您的位置:首页 > 其它

【bzoj4552】[Tjoi2016&Heoi2016]排序 二分+线段树

2017-10-23 20:58 507 查看
题目描述

给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q位置上的数字。
输入

输入数据的第一行为两个整数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
输出

输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。

样例输入

6 3

1 6 2 5 3 4

0 1 4

1 3 6

0 2 4

3

样例输出

5

题解

二分+线段树

直接求这个数是什么比较困难,但是考虑:如果是判定性问题,询问这个数是否大于等于k的话却十分简单。

并且显然具有单调性,因此可以二分。

二分答案mid,转化为判断q位置是否大于等于mid。考虑把大于等于mid的数看作1,小于mid的数看作0,那么每次降序排序相当于把区间中的1放到前面,0放到后面;升序排序相反。

因此可以使用线段树来实现这个过程。最后这个位置如果是1则可行,否则不可行。

时间复杂度$O(n\log^2n)$

#include <cstdio>
#define N 100010
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
int a
, v
, sum[N << 2] , tag[N << 2] , opt
, x
, y
;
inline void pushup(int x)
{
sum[x] = sum[x << 1] + sum[x << 1 | 1];
}
inline void pushdown(int l , int r , int x)
{
if(~tag[x])
{
int mid = (l + r) >> 1;
sum[x << 1] = tag[x] * (mid - l + 1) , tag[x << 1] = tag[x];
sum[x << 1 | 1] = tag[x] * (r - mid) , tag[x << 1 | 1] = tag[x];
tag[x] = -1;
}
}
void build(int l , int r , int x)
{
tag[x] = -1;
if(l == r)
{
sum[x] = v[l];
return;
}
int mid = (l + r) >> 1;
build(lson) , build(rson);
pushup(x);
}
void update(int b , int e , int a , int l , int r , int x)
{
if(b <= l && r <= e)
{
sum[x] = a * (r - l + 1) , tag[x] = a;
return;
}
pushdown(l , r , x);
int mid = (l + r) >> 1;
if(b <= mid) update(b , e , a , lson);
if(e > mid) update(b , e , a , rson);
pushup(x);
}
int query(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e) return sum[x];
pushdown(l , r , x);
int mid = (l + r) >> 1 , ans = 0;
if(b <= mid) ans += query(b , e , lson);
if(e > mid) ans += query(b , e , rson);
return ans;
}
int main()
{
int n , m , q , i , l , r , mid , ans = 0 , t;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]);
for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d" , &opt[i] , &x[i] , &y[i]);
scanf("%d" , &q);
l = 1 , r = n;
while(l <= r)
{
mid = (l + r) >> 1;
for(i = 1 ; i <= n ; i ++ ) v[i] = (a[i] >= mid);
build(1 , n , 1);
for(i = 1 ; i <= m ; i ++ )
{
t = query(x[i] , y[i] , 1 , n , 1) , update(x[i] , y[i] , 0 , 1 , n , 1);
if(t)
{
if(opt[i]) update(x[i] , x[i] + t - 1 , 1 , 1 , n , 1);
else update(y[i] - t + 1 , y[i] , 1 , 1 , n , 1);
}
}
if(query(q , q , 1 , n , 1)) ans = mid , l = mid + 1;
else r = mid - 1;
}
printf("%d\n" , ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: