「TJOI / HEOI2016」排序

原创 2018年04月16日 14:09:36

「TJOI / HEOI2016」排序

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

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

n,m105


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

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

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

所以我们只需要二分一下val即可在O(mlog2n)内解决该题。

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;
}

数据结构基础系列(9):排序

数据结构课程是计算机类专业的专业基础课程,在IT人才培养中,起着重要的作用。课程按照大学计算机类专业课程大纲的要求,安排教学内容,满足需要系统学习数据结构的人。系列课程包含11个部分,本课为第9部分排序,介绍插入排序、交换排序、选择排序、归并排序、基数排序等各种排序算法,以及各种算法的性能分析。
  • 2015年11月25日 22:02

【TJOI2016&&HEOI2016】排序

DescriptionSolution想不出来啊…… 用c++的STL打了个暴力!方法超级机智首先排序是满足二分性质的,那么我们二分出第q个位置是mid,那么≥mid的数全化为1,Code#incl...
  • doyouseeman
  • doyouseeman
  • 2016-07-13 21:56:54
  • 388

【Tjoi2016&Heoi2016】排序

Description 在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个...
  • sadnohappy
  • sadnohappy
  • 2016-07-12 19:24:15
  • 545

BZOJ 4552: [Tjoi2016&Heoi2016]排序

BC #76 这题目好鏼啊! (我也不知道怎么就满足二分性了) #include #include #include #include #include #include #include #i...
  • nlj1999
  • nlj1999
  • 2016-05-20 15:49:21
  • 349

【TJOI2016&&HEOI2016】序列

DescriptionSolution比赛时乱水开始打题后最先想了这一题:第一题太水,第二题太机智,没办法啊……TAT 然后打了个LIS(用二分n log n进行DP,得出最长不下降子序列)进行暴搜...
  • doyouseeman
  • doyouseeman
  • 2016-07-14 19:54:52
  • 888

[Tjoi2016&Heoi2016]树

Description在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,...
  • WorldWide_D
  • WorldWide_D
  • 2016-07-11 15:59:07
  • 555

bzoj4553【TJOI2016&HEOI2016】序列

DP+CDQ分治
  • AaronGZK
  • AaronGZK
  • 2016-06-15 00:13:39
  • 1492

Tjoi2016&Heoi2016 求和

题目 求f(n)f(n)模998244353(7×17×223+1)998244353(7×17×2^{23}+1)看到模数这么奇怪的模数,很容易想到ntt啦正解首先我们看第二类斯特林数的意义S(n...
  • samjia2000
  • samjia2000
  • 2016-07-14 08:31:17
  • 675

【Tjoi2016&Heoi2016】树

Description 在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作: 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其...
  • sadnohappy
  • sadnohappy
  • 2016-07-12 16:37:49
  • 324

【TJOI2016&&HEOI2016】字符串

DescriptionSolution比赛的时候没有时间打,其实这题并不难TAT后缀数组求一段LCP的最大值,明显可以用后缀数组解决。二分先找出c开头的后缀的rank(及rank[c])。 看到最大...
  • doyouseeman
  • doyouseeman
  • 2016-07-13 22:21:28
  • 852
收藏助手
不良信息举报
您举报文章:「TJOI / HEOI2016」排序
举报原因:
原因补充:

(最多只允许输入30个字)