zoukankan      html  css  js  c++  java
  • SPOJ 227 Ordering the Soldiers 线段树 / 树状数组

    题意:设原数组为a[i],pos[i]代表第 i 个位置之前有多少个数比a[i]大,求原数组a[i]。

    这个题意是看了别人的题解才明白,我自己没读出来……

    方法:假设我们从左往右放,因为后面的数还有可能影响前面的数的位置,所以在最后一个数放完之前,我们没法确定每个数的位置,所以我们反过来考虑,从右往左放。因为每个数前面比它大的数的个数pos[i]已知,我们可以不必关心这些数的具体数值,从而转化为它从右往左走了多少个空格,即pos[i]个,因此这个数放在第 pos[i] + 1 个空格位置上。这个空格所在位置的下标id,即是a[i]。a[i] = id;

    树状数组或线段树记录区间[1, i ]的空格个数,对于放好的数,相应区间的空格数减1。

    树状数组代码:5360 ms

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    
    const int MAXN = 200010;
    
    int pos[MAXN];
    int C[MAXN];
    int ans[MAXN];
    bool vis[MAXN];
    int N;
    
    int lowbit( int x )
    {
        return x&(-x);
    }
    
    void Add( int x, int val )
    {
        while ( x <= N )
        {
            C[x] += val;
            x += lowbit(x);
        }
        return;
    }
    
    int Query( int x )
    {
        int res = 0;
        while ( x > 0 )
        {
            res += C[x];
            x -= lowbit(x);
        }
        return res;
    }
    
    //注意二分查找的写法,不然很容易死循环
    void BiSearch( int l, int r, int val, int &addr )
    {
        int mid;
        while ( l <= r )
        {
            mid = ( l + r ) >> 1;
            int sum = Query( N ) - Query( mid - 1 );
            //printf( "mid=%d sum=%d
    ", mid, sum );
            if ( sum > val ) l = mid + 1;
            else
            {
                if ( sum == val )
                {
                    if ( !vis[mid] ) //需要特殊判断一下这个点之前是否已经放好了
                    {
                        addr = mid;
                        r = mid - 1;
                    }
                    else
                    {
                        l = mid + 1;
                    }
                }
                else r = mid - 1;
            }
        }
        return;
    }
    
    int main()
    {
        int T;
        scanf( "%d", &T );
        while ( T-- )
        {
            scanf( "%d", &N );
            memset( C, 0, sizeof(int)*( N + 1 ) );
            memset( vis, false, sizeof(bool)*( N + 1 ) );
            for ( int i = 1; i <= N; ++i )
            {
                scanf( "%d", &pos[i] );
                Add( i, 1 );
            }
    
            for ( int i = N; i > 0; --i )
            {
                int id;
                BiSearch( 1, N, pos[i] + 1, id );
                ans[i] = id;
                vis[id] = true;
                //printf( "id = %d
    ", id );
                Add( id, -1 );
            }
            printf( "%d", ans[1] );
            for ( int i = 2; i <= N; ++i )
                printf( " %d", ans[i] );
            puts("");
        }
        return 0;
    }
    View Code

    线段树代码:1840 ms

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    
    const int MAXN = 200010;
    
    int pos[MAXN];
    int sum[MAXN << 2];
    int ans[MAXN];
    int N, id;
    
    void build( int l, int r, int rt )
    {
        sum[rt] = r - l + 1;
        if ( l == r ) return;
    
        int m = ( l + r ) >> 1;
        build( lson );
        build( rson );
        return;
    }
    
    void Update( int po, int l, int r, int rt )
    {
        --sum[rt];
        if ( l == r )
        {
            id = l;
            return;
        }
    
        int m = ( l + r ) >> 1;
    
        if ( po <= sum[rt << 1] ) Update( po, lson );
        else Update( po - sum[rt << 1], rson );
    
        return;
    }
    
    int main()
    {
        int T;
        scanf( "%d", &T );
        while ( T-- )
        {
            scanf( "%d", &N );
            build( 1, N, 1 );
            for ( int i = 1; i <= N; ++i )
                scanf( "%d", &pos[i] );
    
            for ( int i = N; i > 0; --i )
            {
                Update( pos[i] + 1, 1, N, 1 );
                ans[i] = N - id + 1;
            }
            printf( "%d", ans[1] );
            for ( int i = 2; i <= N; ++i )
                printf( " %d", ans[i] );
            puts("");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Fiddler常用命令
    在Fiddler中添加自己所需的显示列
    清除微信小程序的缓存
    关于接口幂等性的一些总结
    外边距塌陷如何解决?
    CSS背景属性
    CSS链接伪类:超链接的状态
    CSS三大特性
    CSS块元素、行内元素、行内块元素的转换
    CSS行内块元素(内联元素)
  • 原文地址:https://www.cnblogs.com/GBRgbr/p/3223343.html
Copyright © 2011-2022 走看看