首页 > 代码库 > 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 ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。