English Vietnamese Given a sequence of n numbers a1, a2, …, an and a number of d-queries. A d-query is a pair (i, j) (1 ≤ i ≤ j ≤ n). For each d-query (i, j), you have to return the number of distinct elements in the subsequence ai, ai+1, …, aj.
Input Line 1: n (1 ≤ n ≤ 30000). Line 2: n numbers a1, a2, …, an (1 ≤ ai ≤ 106). Line 3: q (1 ≤ q ≤ 200000), the number of d-queries. In the next q lines, each line contains 2 numbers i, j representing a d-query (1 ≤ i ≤ j ≤ n). Output For each d-query (i, j), print the number of distinct elements in the subsequence ai, ai+1, …, aj in a single line. Example Input 5 1 1 2 1 3 3 1 5 2 4 3 5
Output 3 2 3 好久之前就做了這個題目了,但是一直沒有寫篇博客,也是因為一直不太理解吧。 查詢區間有多少種數,查詢次數 和 數列長度 都很大。一開始想有沒有前綴和的關系,大失所望,沒有。。例如 1 2 2 1 3 1位置和4位置都有1 1 到 3 有 2 種數 1 到 5 有 3 種數 ,那相減就是 4 到 5 有1種數 答案顯然是2種數 因為 前面的區間和后面的區間有相同的數 ,這樣相減就會忽略后面的數。所以我們要對 m 次查詢進行離線化 ,按右邊界r從小到大進行排序 然后數列中相同的數只保留最后一次出現的位置 ,之前出現過的位置的c值就要-1。這樣就不用遍歷n*q遍了。 代碼如下:
#include <bits/stdc++.h>
#define ll long long
using namespace std
; const int maxx
= 2e5 + 100 ;
struct node
{ int id
; int l
; int r
; bool operator < ( const node
& a
) const { return a
. r
> r
; }
} p
[ maxx
] ;
map
< int , int > mp
;
int a
[ maxx
] , c
[ maxx
] , ans
[ maxx
] ;
int n
, m
; inline void init ( )
{ mp
. clear ( ) ; memset ( c
, 0 , sizeof ( c
) ) ;
}
inline int lowbit ( int x
) { return x
& ( - x
) ; }
inline void update ( int cur
, int v
) { while ( cur
<= maxx
) c
[ cur
] + = v
, cur
+ = lowbit ( cur
) ; }
inline int query ( int cur
) { int sum
= 0 ; while ( cur
> 0 ) sum
+ = c
[ cur
] , cur
- = lowbit ( cur
) ; return sum
; }
int main ( )
{ while ( ~ scanf ( "%d" , & n
) ) { init ( ) ; for ( int i
= 1 ; i
<= n
; i
++ ) scanf ( "%d" , & a
[ i
] ) ; scanf ( "%d" , & m
) ; for ( int i
= 1 ; i
<= m
; i
++ ) scanf ( "%d%d" , & p
[ i
] . l
, & p
[ i
] . r
) , p
[ i
] . id
= i
; sort ( p
+ 1 , p
+ 1 + m
) ; int cnt
= 1 ; for ( int i
= 1 ; i
<= m
; i
++ ) { for ( int j
= cnt
; j
<= p
[ i
] . r
; j
++ ) { if ( mp
[ a
[ j
] ] ) update ( mp
[ a
[ j
] ] , - 1 ) ; mp
[ a
[ j
] ] = j
; update ( j
, 1 ) ; } cnt
= p
[ i
] . r
+ 1 ; ans
[ p
[ i
] . id
] = query ( p
[ i
] . r
) - query ( p
[ i
] . l
- 1 ) ; } for ( int i
= 1 ; i
<= m
; i
++ ) printf ( "%d%c" , ans
[ i
] , '\n' ) ; } return 0 ;
}
這是樹狀數組||線段樹+離線做法。 主席樹也可以求區間種類數。因為主席樹把之前各個歷史版本都能保存下來,這樣我們就不用離線做了,就可以直接在線做了。但是還是如果之前出現過了,就在之前的版本減一,在當前版本加一。然后再右端點這個版本求(l,r)的種類數。 代碼如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std
; const int maxn
= 30000 + 10 ;
int n
, q
;
int cnt
= 0 ;
struct Node
{ int l
, r
, sum
;
} p
[ maxn
* 40 ] ; int la
[ 1000000 + 10 ] ;
int a
[ maxn
] ;
int root
[ maxn
] ; int build ( int l
, int r
) { int nc
= ++ cnt
; p
[ nc
] . sum
= 0 ; p
[ nc
] . l
= p
[ nc
] . r
= 0 ; if ( l
== r
) return nc
; int m
= l
+ r
>> 1 ; p
[ nc
] . l
= build ( l
, m
) ; p
[ nc
] . r
= build ( m
+ 1 , r
) ; return nc
;
} int update ( int pos
, int c
, int v
, int l
, int r
)
{ int nc
= ++ cnt
; p
[ nc
] = p
[ c
] ; p
[ nc
] . sum
+ = v
; if ( l
== r
) return nc
; int m
= l
+ r
>> 1 ; if ( m
>= pos
) { p
[ nc
] . l
= update ( pos
, p
[ c
] . l
, v
, l
, m
) ; } else { p
[ nc
] . r
= update ( pos
, p
[ c
] . r
, v
, m
+ 1 , r
) ; } return nc
;
} int query ( int pos
, int c
, int l
, int r
) { if ( l
== r
) return p
[ c
] . sum
; int m
= l
+ r
>> 1 ; if ( m
>= pos
) { return p
[ p
[ c
] . r
] . sum
+ query ( pos
, p
[ c
] . l
, l
, m
) ; } else return query ( pos
, p
[ c
] . r
, m
+ 1 , r
) ;
} int main ( )
{ scanf ( "%d" , & n
) ; memset ( la
, - 1 , sizeof la
) ; for ( int i
= 1 ; i
<= n
; ++ i
) { scanf ( "%d" , a
+ i
) ; } root
[ 0 ] = build ( 1 , n
) ; for ( int i
= 1 ; i
<= n
; ++ i
) { int v
= a
[ i
] ; if ( la
[ v
] == - 1 ) { root
[ i
] = update ( i
, root
[ i
- 1 ] , 1 , 1 , n
) ; } else { int t
= update ( la
[ v
] , root
[ i
- 1 ] , - 1 , 1 , n
) ; root
[ i
] = update ( i
, t
, 1 , 1 , n
) ; } la
[ v
] = i
; } scanf ( "%d" , & q
) ; while ( q
-- ) { int x
, y
; scanf ( "%d %d" , & x
, & y
) ; printf ( "%d\n" , query ( x
, root
[ y
] , 1 , n
) ) ; } return 0 ;
}
努力加油a啊,(o )/~
總結
以上是生活随笔 為你收集整理的D-query SPOJ - DQUERY(求区间不同数的个数)(树状数组||线段树+离散)(主席树+在线) 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。