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


    题目描述

    给出一个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(nlog^2n)$

    #include <cstdio>
    #define N 100010
    #define lson l , mid , x << 1
    #define rson mid + 1 , r , x << 1 | 1
    int a[N] , v[N] , sum[N << 2] , tag[N << 2] , opt[N] , x[N] , y[N];
    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
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    android
    需求分析
    请简述使用MediaRecorder实现录音的步骤
    AudioManager的详细内容
    ios 开发failed to chmod
    崩溃block
    图片不能切割成功 调了五个小时!!!!
    collectionView itemW宽度计算不对
    只用头文件
    ping 10.13.5.233
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7718901.html
Copyright © 2020-2023  润新知