「TJOI / HEOI2016」排序

4 篇文章 0 订阅
1 篇文章 0 订阅

「TJOI / HEOI2016」排序

给定一个 1 1 ~n的排列,进行 m m 次以下操作:
0 l r:将区间 [l,r] [ l , r ] 内的数降序排列
1 l r: 1   l   r : 将区间 [l,r] [ l , r ] 内的数升序排列

最后,给定一个位置,求出该位置的数。

n,m105 n , m ≤ 10 5


我们知道,对一个 01 01 串进行上述操作非常容易,用线段树就可以在 logn l o g n 的时间内完成一次操作。

我们考虑一下可不可以将这个问题转换为对 01 01 串的操作。

我们取一个数 val v a l ,设大于等于 val v a l 的值为 1 1 ,小于val的值为 0 0 。这样我们操作后,如果询问的位置为1,说明答案大于等于 val v a l ,否则说明答案小于 val v a l ,而一次操作是 O(mlogn) O ( m l o g n ) 的。

所以我们只需要二分一下 val v a l 即可在 O(mlog2n) O ( m l o g 2 n ) 内解决该题。

code:

#include <bits/stdc++.h>
using namespace std;
const int N = 100000;

int n, m, pos, a[N];

struct tModify {
    int type, l, r;
} mdf[N];

struct tData {
    int sum_0, sum_1;
    tData() { sum_0 = sum_1 = 0; }
    tData( int _sum_0, int _sum_1 ) { sum_0 = _sum_0; sum_1 = _sum_1; }

    tData operator + ( const tData &rhs ) const {
        return ( tData ) { sum_0 + rhs.sum_0, sum_1 + rhs.sum_1 };
    }
} now;

struct segment_tree {
    int sum[2][N<<2], opt[N<<2];  
    #define lson (o<<1)
    #define rson (o<<1|1)
    inline void pushup( int o, int l, int r ) {
        sum[0][o] = sum[0][lson] + sum[0][rson];
        sum[1][o] = sum[1][lson] + sum[1][rson];

        assert( sum[0][o] + sum[1][o] == r - l + 1 );
    }
    #define pushup( o ) pushup( o, l, r )
    inline void pushdown( int o, int l, int r )
    {
        if( opt[o] == -1 ) return;
        int mid = l + r >> 1, tp = opt[o];

        sum[tp][lson] = mid - l + 1; 
        sum[tp][rson] = r - mid;
        sum[tp^1][lson] = sum[tp^1][rson] = 0;
        opt[lson] = opt[rson] = tp;
        opt[o] = -1;
    }
    inline void build( int o, int l, int r, int val )
    {
        opt[o] = -1;
        if( l == r ) {
            sum[a[l]>=val][o] = 1, sum[a[l]<val][o] = 0; return;
            // if( a[l] >= val ) --> 1, else --> 0
        }
        int mid = l + r >> 1;

        build( lson, l, mid, val );
        build( rson,mid+1,r, val );
        pushup( o );
    }
    inline tData query( int o, int l, int r, int ql, int qr ) 
    {   
        if( ql <= l && r <= qr ) return ( tData ) { sum[0][o], sum[1][o] };
        pushdown( o, l, r ); int mid = l + r >> 1; tData ret;

        if( ql <= mid ) ret = ret + query( lson, l, mid, ql, qr );
        if( mid+1<=qr ) ret = ret + query( rson,mid+1,r, ql, qr );
        pushup( o );
        return ret;
    }
    inline void modify_up( int o, int l, int r, int ql, int qr )
    {
        pushdown( o, l, r );
        int mid = l + r >> 1, len = r - l + 1;
        if( ql <= l && r <= qr ) 
        {
            if( now.sum_0 >= len ) {
                sum[0][o] = len, sum[1][o] = 0, opt[o] = 0, now.sum_0 -= len; return;
            }
            if( !now.sum_0 ) {
                sum[1][o] = len, sum[0][o] = 0, opt[o] = 1, now.sum_1 -= len; return;
            }

            modify_up( lson, l, mid, ql, qr );
            modify_up( rson,mid+1,r, ql, qr );
            pushup( o ); return;
        }

        if( ql <= mid ) modify_up( lson, l, mid, ql, qr );
        if( mid+1<=qr ) modify_up( rson,mid+1,r, ql, qr );
        pushup( o );
    }
    inline void modify_down( int o, int l, int r, int ql, int qr ) 
    {
        pushdown( o, l, r );
        int mid = l + r >> 1, len = r - l + 1;
        if( ql <= l && r <= qr ) 
        {
            if( now.sum_1 >= len ) {
                sum[1][o] = len, sum[0][o] = 0, opt[o] = 1, now.sum_1 -= len; return;
            }
            if( !now.sum_1 ) {
                sum[0][o] = len, sum[1][o] = 0, opt[o] = 0, now.sum_0 -= len; return;
            }

            modify_down( lson, l, mid, ql, qr );
            modify_down( rson,mid+1,r, ql, qr );
            pushup( o ); return;
        }

        if( ql <= mid ) modify_down( lson, l, mid, ql, qr );
        if( mid+1<=qr ) modify_down( rson,mid+1,r, ql, qr );
        pushup( o );
    }
    inline void print( int o, int l, int r )
    {
        if( l == r ) {
            printf( "%d ", sum[1][o] == 1 ); return;
        }
        int mid = l + r >> 1; pushdown( o, l, r );

        print( lson, l, mid );
        print( rson,mid+1,r );
        pushup( o );
    }
    #undef lson
    #undef rson
} seg;

tData tmp; int ans;

inline bool check( int val )
{
    seg.build( 1, 1, n, val );
//  seg.print( 1, 1, n ); printf( "\n" );
    for( int i = 1; i <= m; i ++ )
    {
        now = seg.query( 1, 1, n, mdf[i].l, mdf[i].r );
        if( mdf[i].type )
            seg.modify_down( 1, 1, n, mdf[i].l, mdf[i].r );
        else seg.modify_up( 1, 1, n, mdf[i].l, mdf[i].r );
    }

//  seg.print( 1, 1, n ); printf( "\nval:%d\n",val ); 

    now = seg.query( 1, 1, n, pos, pos );
//    printf( "val:%d, tmp:%d %d\n", val, now.sum_0, now.sum_1 );
    return now.sum_1 == 1;
}

void solve( int l, int r )
{
    if( l > r ) return;

    int mid = l + r >> 1;
    bool b = check( mid );

    if( b ) {
        ans = mid; solve( mid+1, r );
    }
    else solve( l, mid-1 );
}

int main()
{
//  freopen( "sort4.in", "r", stdin );

    scanf( "%d%d", &n, &m );
    for( int i = 1; i <= n; i ++ )
        scanf( "%d", &a[i] );

    for( int i = 1; i <= m; i ++ )
        scanf( "%d%d%d", &mdf[i].type, &mdf[i].l, &mdf[i].r );

    scanf( "%d", &pos );

    solve( 1, n );

    printf( "%d\n", ans );

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值