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

}
主席树解法
#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;

}
按照这个思路倒是很正确

 

你可能感兴趣的:(super)