主席树求区间内不同数字的个数
例题:[SDOI2009]HH的项链(然而我的主席树无论如何都会被加强的数据卡到72分)
题目搬运:
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
第一行:一个整数N,表示项链的长度。
第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。
第三行:一个整数M,表示HH 询问的个数。
接下来M 行:每行两个整数,L 和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
解题思路
我们对于每个数,用last记录它前面第一个与它相同的数的位置,如果没有,则记为0。
然后对应的主席树上的每一个叶节点储存的就是以这个叶子结点的编号为last i 的个数。
然后,一个普通的主席树(就被CZ加强数据卡)
版本一:65分
#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std ;
const int MAXN = 1000005 ;
inline int read(){
int s=0 ; char g=getchar() ; while(g>'9'||g<'0')g=getchar() ;
while( g>='0'&&g<='9')s=s*10+g-'0',g=getchar() ; return s ;
}
struct Seg{
int l , r , sum ;
}t[ MAXN<<5 ];
int a[ MAXN ] , last[ MAXN ] , b[ MAXN ] , root[ MAXN ] , N , M , ma=0 , cnt = 0 ;
void copyNode( int x , int y ){
t[ x ].l = t[ y ].l , t[ x ].r = t[ y ].r , t[ x ].sum = t[ y ].sum+1 ;
}
void build( int p , int l , int r ){
t[ p ].sum = 0 ;
if( l ==r )return ;
int mid = ( l+r )>>1 ;
build( t[ p ].l = ++cnt , l , mid ) ;
build( t[ p ].r = ++cnt , mid+1 , r ) ;
}
int New_made( int las , int l , int r , int val ){
int p = ++cnt ;
copyNode( p , las ) ;
if( l == r )return p ;
int mid = ( l+r )>>1 ;
if( val <= mid )t[ p ].l = New_made( t[ p ].l , l , mid , val ) ;
else t[ p ].r = New_made( t[ p ].r , mid+1 , r , val ) ;
return p ;
}
int ask( int x , int y , int l , int r , int ll ,int rr ){
if( l >= ll && r <= rr )return t[ x ].sum - t[ y ].sum ;
int mid = ( l+r )>>1 ;
int val = 0 ;
if( ll <= mid )val = ask( t[ x ].l , t[ y ].l , l , mid , ll , rr ) ;
if( rr > mid )val += ask( t[ x ].r , t[ y ].r , mid+1 , r , ll , rr ) ;
return val ;
}
/*void Debug( int p , int p2 , int l , int r ){
if( l == r ){
printf("%d ",t[ p ].sum - t[ p2 ].sum ) ; return ;
}
int mid = (l+r )>>1 ;
Debug( t[ p ].l , t[ p2 ].l , l , mid );
Debug( t[ p ].r , t[ p2 ].r , mid+1 , r );
}*/
int main(){
N = read() ;
for( int i = 1 ; i <= N ; ++i )
a[ i ] = read() , last[ i ] = b[ a[ i ] ] , b[ a[ i ] ] = i , ma = max( last[ i ] , ma ) ;
M = read() ;
build( root[0] = ++cnt , 0 , ma ) ;//0~ma
for( int i = 1 ; i <= N ; ++i )root[ i ] = New_made( root[ i-1 ] , 0 , ma , last[ i ] ) ;
int m1 , m2 ;
for( int i = 1 ; i <= M ; ++i ){
m1 = read() , m2 = read() ;
printf("%d
",m2 - m1 + 1 - ask( root[ m2 ] , root[ m1-1 ] , 0 , ma , m1 , m2 ) ) ;
}
//Debug( root[ 99 ] , root[ 14 ] , 0 , ma ) ;
return 0 ;
}
版本二:72分
#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std ;
const int MAXN = 1000005 ;
inline int read(){
int s=0 ; char g=getchar() ; while(g>'9'||g<'0')g=getchar() ;
while( g>='0'&&g<='9')s=s*10+g-'0',g=getchar() ; return s ;
}
struct Seg{
int l , r , sum ;
}t[ MAXN<<5 ];
int a[ MAXN ] , last[ MAXN ] , b[ MAXN ] , root[ MAXN ] , N , M , ma=0 , cnt = 0 ;
void copyNode( int x , int y ){
t[ x ].l = t[ y ].l , t[ x ].r = t[ y ].r , t[ x ].sum = t[ y ].sum+1 ;
}
void build( int p , int l , int r ){
t[ p ].sum = 0 ;
if( l ==r )return ;
int mid = ( l+r )>>1 ;
build( t[ p ].l = ++cnt , l , mid ) ;
build( t[ p ].r = ++cnt , mid+1 , r ) ;
}
int New_made( int las , int l , int r , int val ){
int p = ++cnt ;
copyNode( p , las ) ;
if( l == r )return p ;
int mid = ( l+r )>>1 ;
if( val <= mid )t[ p ].l = New_made( t[ p ].l , l , mid , val ) ;
else t[ p ].r = New_made( t[ p ].r , mid+1 , r , val ) ;
return p ;
}
int ask( int x , int y , int rr, int l ,int r ){
if( r <= rr)return t[ x ].sum - t[ y ].sum ;
int mid=(l+r)>>1 , val = ask(t[ x ].l , t[ y ].l , rr, l , mid );
if( mid < rr )val+=ask(t[ x ].r , t[y].r , rr , mid+1 , r );
return val;
}
/*void Debug( int p , int p2 , int l , int r ){
if( l == r ){
printf("%d ",t[ p ].sum - t[ p2 ].sum ) ; return ;
}
int mid = (l+r )>>1 ;
Debug( t[ p ].l , t[ p2 ].l , l , mid );
Debug( t[ p ].r , t[ p2 ].r , mid+1 , r );
}*/
int main(){
N = read() ;
for( int i = 1 ; i <= N ; ++i )
a[ i ] = read() , last[ i ] = b[ a[ i ] ] , b[ a[ i ] ] = i , ma = max( last[ i ] , ma ) ;
M = read() ;
build( root[0] = ++cnt , 0 , ma ) ;//0~ma
for( int i = 1 ; i <= N ; ++i )root[ i ] = New_made( root[ i-1 ] , 0 , ma , last[ i ] ) ;
int m1 , m2 ;
for( int i = 1 ; i <= M ; ++i ){
m1 = read() , m2 = read() ;
printf("%d
",ask( root[ m2 ] , root[ m1-1 ] , m1-1 , 0 , ma ) ) ;
}
//Debug( root[ 99 ] , root[ 14 ] , 0 , ma ) ;5831587 2793261
return 0 ;
}