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

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

 

 

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序列进行离散化

 

#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 100005int 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;}
主席树解法
#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 100005int 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 ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )