structBIT { /* ======================================== */ ll tr[maxn]; int sz; voidinit( int N ){ sz = N; fill( tr, tr + sz + 2, 0 ); } voidadd( int idx, ll val ){ for( int i = idx; i <= sz; i += i & -i ) tr[i] += val; } ll ask( int idx ){ ll res = 0; for( int i = idx; i; i -= i & -i ) res += tr[i]; return res; } ll query( int l, int r ){ returnask( r ) - ask( l - 1 ); } /* ======================================== */ } bit;
int a[maxn]; int lst[maxn]; int ans[maxn];
structQuery { int l, r, id; } qs[maxn];
boolcmp( Query x, Query y ){ return x.r < y.r; }
voidsolve( ){ int n = read( ); for( int i = 1; i <= n; i++ ) a[i] = read( );
int m = read( ); for( int i = 1; i <= m; i++ ) { qs[i].l = read( ); qs[i].r = read( ); qs[i].id = i; }
sort( qs + 1, qs + m + 1, cmp );
bit.init( n );
int cur = 1; for( int i = 1; i <= m; ++ i ) { auto [l, r, id] = qs[i]; for( int j = cur; j <= r; ++ j ) { if( lst[a[j]] ) bit.add( lst[a[j]], -1 ); bit.add( j, 1 ); lst[a[j]] = j; } cur = r + 1; ans[id] = bit.query( l, r ); }
for( int i = 1; i <= m; i++ ) { cout << ans[i] << '\n'; } }
莫队版本
这份实现直接维护当前区间内每种权值的出现次数,是前期思路对应的 AC 代码。它与标准离线树状数组版本解决的是同一问题,但复杂度更高。
boolcmp( Query x, Query y ){ int bx = get_block( x.l ); int by = get_block( y.l ); if( bx != by ) return bx < by; if( bx & 1 ) return x.r > y.r; return x.r < y.r; }
voidadd( int pos ){ int x = a[pos]; if( cnt[x] == 0 ) tot ++; cnt[x]++; }
voiddel( int pos ){ int x = a[pos]; cnt[x]--; if( cnt[x] == 0 ) tot --; }
voidsolve( ){ int n = read( ); for( int i = 1; i <= n; i++ ) a[i] = read( );
int m = read( ); for( int i = 1; i <= m; i++ ) { qs[i].l = read( ); qs[i].r = read( ); qs[i].id = i; }
block = max( 1, (int)( n / sqrt( m ) ) );
sort( qs + 1, qs + m + 1, cmp );
int L = 1, R = 0; for( int i = 1; i <= m; ++ i ) { auto [l, r, id] = qs[i]; while( L > l ) add( -- L ); while( R < r ) add( ++ R ); while( L < l ) del( L ++ ); while( R > r ) del( R -- ); ans[id] = tot; }
for( int i = 1; i <= m; i++ ) { cout << ans[i] << '\n'; } }