• 【BZOJ】2653: middle


    2653: middle

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 2381  Solved: 1340
    [Submit][Status][Discuss]

    Description

    一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。给你一个
    长度为n的序列s。回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
    其中a<b<c<d。位置也从0开始标号。我会使用一些方式强制你在线。

    Input

    第一行序列长度n。接下来n行按顺序给出a中的数。
    接下来一行Q。然后Q行每行a,b,c,d,我们令上个询问的答案是
    x(如果这是第一个询问则x=0)。
    令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
    将q从小到大排序之后,令真正的
    要询问的a=q[0],b=q[1],c=q[2],d=q[3]。  
    输入保证满足条件。
    第一行所谓“排过序”指的是从小到大排序!
    n<=20000,Q<=25000
     

    Output

    Q行依次给出询问的答案。

    Sample Input

    5
    170337785
    271451044
    22430280
    969056313
    206452321
    3
    3 1 0 2
    2 3 1 4
    3 1 4 0

    Sample Output

    271451044
    271451044
    969056313

    HINT

     

    Source

     
    [Submit][Status][Discuss]


    HOME Back

    clj dalao出的神题%%%

    一道很好的思维题吧。首先可以发现,满足条件的中位数是具有二分性(即单调性)的。比如数列中一个数$x$,我们把所有比$x$小的数的位置标记成-1,比$x$大的数的位置标记成1,如果和大于0,表示比它大的数枚举多了,所以把答案往右移,反之往左移。满足二分性,所以二分check时满足区间最大值>=0就表示这个数可以作为答案,更新答案。(<=0也可以用来判断,不过维护的是最小值即可)

    可以发现,问题中的$bc$区间一定被包括,所以查询$ab$的右缀连续区间最大值和$cd$的左缀连续区间最大值以及$bc$的整个区间和即可。【注意】所有区间都是左闭右开。

    考虑如何维护。给每个值建一棵主席数,预处理出每棵主席数上-1和1的情况,每次就在对应二分的pos的主席树上查询即可。

    最后是合并节点的问题,$lmax$是从左儿子的$lmax$或者左儿子的$sum$加右儿子的$lmax$更新过来,$rmax$同理。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    int n, ans, a, b, c, d, q[5];
    
    struct QwQ {
        int v, id;
    } A[20005];
    bool cmp ( QwQ a, QwQ b ) { return a.v < b.v; }
    
    struct node {
        node *ls, *rs;
        int sum, lmax, rmax;
        void update ( ) {
            sum = ls -> sum + rs -> sum;
            lmax = max ( ls -> lmax, ls -> sum + rs -> lmax );
            rmax = max ( rs -> rmax, rs -> sum + ls -> rmax );
        }
    } *zero, *root[20005], pool[20005*32], *tail = pool;
    
    node *newnode ( ) {
        node *nd = ++ tail;
        nd -> ls = zero; nd -> rs = zero;
        nd -> sum = 0; nd -> lmax = 0; nd -> rmax = 0;
        return nd;
    }
    
    node *build ( int l, int r ) {
        node *nd = newnode ( );
        if ( l == r ) {
            nd -> sum = nd -> lmax = nd -> rmax = 1; 
            return nd;
        }
        int mid = ( l + r ) >> 1;
        nd -> ls = build ( l, mid );
        nd -> rs = build ( mid + 1, r );
        nd -> update ( );
        return nd;
    }
    
    void init ( ) {
        zero = ++ tail;    
        zero -> ls = zero; zero -> rs = zero; zero -> sum = 0;
        zero -> lmax = 0; zero -> rmax = 0;
        root[1] = build ( 1, n );
    }
    
    node *insert ( node *nd, int l, int r, int pos ) {
        node *nnd = newnode ( );
        if ( l == r ) { nnd -> sum = -1; nnd -> lmax = nnd -> rmax = -1; return nnd; }
        int mid = ( l + r ) >> 1;
        if ( mid >= pos ) {
            nnd -> rs = nd -> rs;
            nnd -> ls = insert ( nd -> ls, l, mid, pos );
         } else {
            nnd -> ls = nd -> ls;
            nnd -> rs = insert ( nd -> rs, mid + 1, r, pos );
         }
        nnd -> update ( );
        return nnd;
    }
    
    int query_s ( node *nd, int l, int r, int L, int R ) {
        if ( L > R ) return 0;
        if ( l >= L && r <= R ) return nd -> sum;
        int mid = ( l + r ) >> 1, ans = 0;
        if ( L <= mid ) ans += query_s ( nd -> ls, l, mid, L, R );
        if ( R > mid ) ans += query_s ( nd -> rs, mid + 1, r, L, R );
        return ans;
    }
    
    int query_l ( node *nd, int l, int r, int L, int R ) {
        if ( L > R ) return 0;
        if ( l >= L && r <= R ) return nd -> lmax;
        int mid = ( l + r ) >> 1, ans = 0;
        if ( L <= mid ) ans = max ( ans, query_l ( nd -> ls, l, mid, L, R ) );
        if ( R > mid ) {
            int lsum = query_s ( nd -> ls, l, mid, L, mid );
            int rmaxl = query_l ( nd -> rs, mid + 1, r, L, R );
            ans = max ( ans, lsum + rmaxl );
        }
        return ans;
    }
    
    int query_r ( node *nd, int l, int r, int L, int R ) {
        if ( L > R ) return 0;
        if ( l >= L && r <= R ) return nd -> rmax;
        int mid = ( l + r ) >> 1, ans = 0;
        if ( R > mid ) ans = max ( ans, query_r ( nd -> rs, mid + 1, r, L, R ) );
        if ( L <= mid ) {
            int rsum = query_s ( nd -> rs, mid + 1, r, mid + 1, R );
            int lmaxr = query_r ( nd -> ls, l, mid, L, R );
            ans = max ( ans, rsum + lmaxr );
        }
        return ans;
    }
    
    bool check ( int pos ) {
        int ab = query_r ( root[pos], 1, n, a, b - 1 );
        int cd = query_l ( root[pos], 1, n, c + 1, d );
        int bc = query_s ( root[pos], 1, n, b, c );
        if ( ab + cd + bc >= 0 ) return 1;
        return 0;
    }
    
    int find ( ) {
        int l = 1, r = n, ans = 0;
        while ( l <= r ) {
            int mid = ( l + r ) >> 1;
            if ( check ( mid ) ) {
                ans = mid; l = mid + 1;
            } else r = mid - 1;
        }
        return ans;
    }
    
    int main ( ) {
        scanf ( "%d", &n );
        init ( );
        for ( int i = 1; i <= n; i ++ )    {
            scanf ( "%d", &A[i].v ); A[i].id = i;
        }
        sort ( A + 1, A + 1 + n, cmp );
        for ( int i = 2; i <= n; i ++ )
            root[i] = insert ( root[i-1], 1, n, A[i-1].id );
        int Q;
        scanf ( "%d", &Q );
        while ( Q -- ) {
            for ( int i = 1; i <= 4; i ++ ) {
                int x; scanf ( "%d", &x );
                q[i] = ( x + ans ) % n + 1;
            }
            sort ( q + 1, q + 5 );
            a = q[1], b = q[2], c = q[3], d = q[4];
            ans = A[find ( )].v;
            printf ( "%d
    ", ans );
        }
        return 0;
    }
  • 相关阅读:
    pandas 数据预处理实例演示
    pandas 包的基本使用
    Numpy 包的基础结构(下)
    Numpy 包的基础结构(上)
    Anaconda的基本使用
    黄金点游戏结果
    个人作业-Week2:案例分析
    结对项目-地铁出行路线规划程序(续)
    关于结对和团队组建
    关于个人博客和Github地址提交
  • 原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9507990.html
Copyright © 2020-2023  润新知