1. 程式人生 > >SPOJ - DQUERY: D-query 離線處理 + 樹狀數組

SPOJ - DQUERY: D-query 離線處理 + 樹狀數組

find style splay can 問題 its 序列 處理 alt

題目鏈接:https://vjudge.net/problem/SPOJ-DQUERY

題意:給定數字序列,求任意區間內的不同數字的個數

解法:用樹狀數組維護 1 ~ i 的區間內不同數字個數的前綴和,首要解決的問題就是同一區間內相同數字統計時相互影響的問題,解決方法如下:離線存儲查詢的區間,對查詢區間按照左端點排序,這樣可以優先處理左邊的 元素;然後預處理出每一元素下一跳到相同元素的 nxt[]; 這樣隨著坐標軸指針 l 的移動,l 左邊的元素將不會產生任何影響,因為所產生的影響會在前綴和的做差運算中抵消;只需要對 l 指針左區間的元素的下一跳的位 置進行 add + 1 操作,從而更新當前查詢區間的信息。

BIT代碼實現:

技術分享
 1 //190ms    19.5MB
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 
 5 const int N = 30010;
 6 const int M = 200010;
 7 int a[N], bit[N];
 8 
 9 void init() {
10     memset(bit, 0, sizeof(bit));
11 }
12 
13 int lowbit(int x) {
14     return x & -x;
15 }
16 
17
void add(int x, int val) { 18 while(x < N) { 19 bit[x] += val; 20 x += lowbit(x); 21 } 22 } 23 24 int sum(int x) { 25 int ret = 0; 26 while(x > 0) { 27 ret += bit[x]; 28 x -= lowbit(x); 29 } 30 return ret; 31 } 32 33 struct
Query{ 34 int l, r, p; 35 bool operator < (const Query& p)const{ 36 return l < p.l; 37 } 38 } query[M]; 39 int n, q; 40 map<int, int> mp; 41 int nxt[N], ans[M]; 42 43 int main() 44 { 45 scanf("%d", &n); 46 mp.clear(); 47 init(); 48 for (int i = 1; i <= n; ++ i) { 49 scanf("%d", &a[i]); 50 if(mp.find(a[i]) == mp.end()) { 51 mp[a[i]] = i; 52 add(i, 1); 53 } 54 } 55 mp.clear(); 56 for (int i = n; i >= 1; -- i) { 57 if(mp.find(a[i]) == mp.end()) nxt[i] = n + 1; 58 else nxt[i] = mp[a[i]]; 59 mp[a[i]] = i; 60 } 61 scanf("%d", &q); 62 for (int i = 1; i <= q; ++ i) { 63 scanf("%d%d", &query[i].l, &query[i].r); 64 query[i].p = i; 65 } 66 sort(query+1, query+1+q); 67 int pp = 1; 68 for (int i = 1; i <= q; ++ i) { 69 while(pp<=n && pp < query[i].l) add(nxt[pp++], 1); 70 ans[query[i].p] = sum(query[i].r) - sum(query[i].l-1); 71 } 72 for (int i = 1; i <= q; ++ i) printf("%d\n", ans[i]); 73 return 0; 74 }
View Code

SPOJ - DQUERY: D-query 離線處理 + 樹狀數組