码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 4417 Super Mario ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )

时间:2014-10-04 19:04:07      阅读:360      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   io   os   ar   for   strong   

 

 

HDU 4417 - Super Mario ( 主席树 + 线段树/树状数组离线处理 + 划分树 )

这道题有很多种做法,我先学习的是主席树。后面陆续补上线段树离线和划分树

题目大意就是给定一个区间
给定一个数列,每次要求你查询区间[L,R]内不超过K的数的数量


 

主席树做法:

最基本的是静态第k大,这里是求静态的 <= K,差不多,在Query操作里面需要修改修改

先建立size棵主席树,然后询问的时候统计的是

第R棵主席树中[1,K]的数量 - 第L-1棵主席树中[1,K]的数量

注意这里下标从0开始,所以是L - R+1

这里有一个疑惑就是为什么用把HH[i]的值也进行建树,不然会RE,怎么回事还不知道

建树的时候记得对K序列进行离散化

 

bubuko.com,布布扣
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define CLR( a, b )        memset( a, b, sizeof(a) )
using namespace std;
    
#define lson l, m, L[o]
#define rson m + 1, r, R[o]
#define MAXN 100005

int L[MAXN << 5], R[MAXN << 5], cnt[MAXN << 5];
int root[MAXN];
int num[MAXN], H[MAXN], tot;
int LL[MAXN], RR[MAXN], HH[MAXN];

void PushUp( int o ){
    cnt[o] = cnt[ L[o] ] + cnt[ R[o] ];
} 

void Build( int l, int r ,int &o ){
    o = tot++;
    cnt[o] = 0;
    if( l == r )    
        return;
    int m = ( l + r ) >> 1;
    Build( lson );
    Build( rson );
}

void Update( int fa, int p, int l, int r ,int &o ){
    o = tot++;
    //printf("o = %d\n tot = %d\n",o,tot);
    L[o] = L[fa];
    R[o] = R[fa];
    cnt[o] = cnt[fa] + 1;
    if( l == r )
        return;

    int m = ( l + r ) >> 1;
    if( p <= m )    Update( L[fa], p, lson );
    else     Update( R[fa], p, rson );
    //PushUp( o );
}

int Query( int u, int v, int l, int r, int ll,int rr ){
    if( ll <= l && r <= rr ){
        return cnt[v] - cnt[u];
    }
    int m = ( l + r ) >> 1, ans = 0;
    if( ll <= m )        ans += Query( L[u], L[v], l, m, ll, rr );
    if( rr >  m )         ans += Query( R[u], R[v], m + 1, r, ll, rr );
    return ans;
}

void Orz(){
    int n, i, h, ans, m, cas, t;
    scanf( "%d", &t );
    for( cas = 1; cas <= t; ++cas ){
        scanf( "%d %d", &n,&m );
        int size = 0;
        for( i = 1; i <= n; ++i ){
            scanf( "%d", &num[i] );
            H[++size] = num[i];
        }
        for( i = 1; i <= m; ++i){
            scanf( "%d %d %d", &LL[i], &RR[i], &HH[i] );
            H[++size] = HH[i];
        }
        sort( H + 1, H + size + 1 );
        size = unique( H + 1, H + size + 1 ) - H - 1;
        tot = 0;
        Build( 1, size, root[0] );
        for( i = 1; i <= n; ++i ){
            num[i] = lower_bound( H + 1, H + size + 1, num[i] ) - H;
        }
        for( i = 1; i <= n; ++i ){
            Update( root[i-1], num[i], 1, size , root[i] );
        }
        printf( "Case %d:\n", cas );
        for( i = 1; i <= m; ++i ){
            h = lower_bound( H + 1, H + size + 1, HH[i] ) - H;
            ans = Query( root[LL[i]], root[RR[i]+1], 1, size, 1, h );
            printf( "%d\n", ans );
        }
    } 
}

int main()                
{
    Orz();
    return 0;
}
主席树解法
bubuko.com,布布扣
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define CLR( a, b )        memset( a, b, sizeof(a) )
using namespace std;


#define lson l, m, L[o]
#define rson m + 1, r, R[o]
#define MAXN 100005

int L[MAXN << 5], R[MAXN << 5], cnt[MAXN << 5];
int root[MAXN];
int num[MAXN], H[MAXN], tot;

void PushUp( int o ){
    cnt[o] = cnt[ L[o] ] + cnt[ R[o] ];
} 

void Build( int l, int r ,int &o ){
    o = tot++;
    cnt[o] = 0;
    if( l == r )    
        return;
    int m = ( l + r ) >> 1;
    Build( lson );
    Build( rson );
}

void Update( int fa, int p, int l, int r ,int &o ){
    o = tot++;
    L[o] = L[fa];
    R[o] = R[fa];
    cnt[o] = cnt[fa] + 1;
    if( l == r )
        return;

    int m = ( l + r ) >> 1;
    if( p <= m )    Update( L[fa], p, lson );
    else     Update( R[fa], p, rson );
    //PushUp( o );
}

int Query( int u, int v, int l, int r, int x ){
    if( l == r )    return ( x < l ) ? 0 : cnt[v] - cnt[u];
    //我们要求区间[L, R]中比h小的数,
    //那么就用 cnt[R] - cnt[L-1]  
    int m = ( l + r ) >> 1;
    if( x <= m )    return Query( L[u], L[v], l, m, x );
    else            return cnt[L[v]] - cnt[L[u]] + Query( R[u], R[v], m + 1, r, x );    
}


void Orz(){
    int n, i, j, h, ans , m, l, r, cas, t;
    scanf( "%d", &t );
    for( cas = 1; cas <= t; ++cas ){
        scanf( "%d %d", &n,&m );
        for( i = 1; i <= n; ++i ){
            scanf( "%d", &num[i] );
            H[i] = num[i];
        }
        sort( H + 1, H + n + 1 );
        int size = unique( H + 1, H + n + 1 ) - H - 1;
        for( i = 1; i <= n; ++i ){
            num[i] = lower_bound( H + 1, H + size + 1, num[i] ) - H;
        }
        tot = 0;
        Build( 1, size, root[0] );
        for( i = 1; i <= n; ++i ){
            Update( root[i-1], num[i], 1, size , root[i] );
        }
        printf( "Case %d:\n", cas);
        while( m-- ){
            scanf( "%d %d %d", &l, &r, &h );
            h = upper_bound( H + 1, H + size + 1, h ) - H - 1;
            ans = Query( root[l], root[r+1], 1, size, h );
            printf( "%d\n", ans );
        }
    } 
}

int main()                
{
    Orz();
    return 0;
}
按照这个思路倒是很正确

 

HDU 4417 Super Mario ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )

标签:style   blog   http   color   io   os   ar   for   strong   

原文地址:http://www.cnblogs.com/BigBallon/p/4006168.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!