zoukankan      html  css  js  c++  java
  • 【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;
    }
    

     

  • 相关阅读:
    hdu 5119 Happy Matt Friends
    hdu 5128 The E-pang Palace
    hdu 5131 Song Jiang's rank list
    hdu 5135 Little Zu Chongzhi's Triangles
    hdu 5137 How Many Maos Does the Guanxi Worth
    hdu 5122 K.Bro Sorting
    Human Gene Functions
    Palindrome(最长公共子序列)
    A Simple problem
    Alignment ( 最长上升(下降)子序列 )
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7718901.html
Copyright © 2011-2022 走看看