SPOJ 3267. D-query (the Chairman tree or tree array is offline), spojd-query
A-D-query
Time Limit:1500 MS
Memory Limit:0 KB
64bit IO Format:% Lld & % lluSubmit Status Practice SPOJ DQUERYAppoint description: System Crawler)
Description
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 51 1 2 1 331 52 43 5 Output 323
The number of different elements in the query interval. You can use a tree array to perform offline operations or use the Chairman tree.
Chairman tree version:
/*************************************** * *********************************> File Name: cf. cpp> Author: acvlinoleic> QQ:> Mail: acvcla@gmail.com> Created Time: 1949 äê 10 *â 1è **************** **************************************** * ***************/# include <iostream> # include <algorithm> # include <cstdio> # include <vector> # include <cstring> # include <map> # include <queue> # include <stack> # include <String> # include <cstdlib> # include <ctime> # include <set> # include <math. h> using namespace std; typedef long LL; const int maxn = 3e4 + 10; # define rep (I, a, B) for (int I = (); I <= (B); I ++) # define pb push_backint tot, n, m, date [maxn], root [maxn]; struct chairTnode {int s, rc, lc; chairTnode (int s = 0, int lc = 0, int rc = 0): s (s), lc (lc), rc (rc ){}}; chairTnode chairT [maxn * 20]; int newnode (int sum, int lson, int rson) {int rt = + + Tot; chairT [rt] = chairTnode (sum, lson, rson); return rt;} void Insert (int & rt, int pre_rt, int pos, int L, int R, int val) {chairTnode & t = chairT [pre_rt]; rt = newnode (t. s + val, t. lc, t. rc); if (L = R) return; int mid = (L + R)> 1; if (pos <= mid) Insert (chairT [rt]. lc, t. lc, pos, L, mid, val); else Insert (chairT [rt]. rc, t. rc, pos, mid + 1, R, val);} int Query (int rt, int L, int R, int pos) // Query sum of [pos, r] {if (L = pos) return chairT [rt ]. S; int mid = (L + R)> 1; if (pos <= mid) return Query (chairT [rt]. lc, L, mid, pos) + chairT [chairT [rt]. rc]. s; return Query (chairT [rt]. rc, mid + 1, R, pos);} int main () {while (~ Scanf ("% d", & n) {rep (I, 1, n) {scanf ("% d", date + I );} tot = root [0] = 0; map <int, int> q; int t; for (int I = 1; I <= n; I ++) {if (! Q [date [I]) {Insert (root [I], root [I-1], I, 1, n, 1 ); // Add 1} else {Insert (t, root [I-1], q [date [I], 1, n,-1) in the number of position I ); // It has already appeared before, minus the Insert (root [I], t, I, 1, n, 1) previously added ); // Add now} q [date [I] = I;} int ql, qr; scanf ("% d", & m); while (m --) {scanf ("% d", & ql, & qr); printf ("% d \ n", Query (root [qr], 1, n, ql) ;}} return 0 ;}
Tree edition:
# Include <iostream> # include <cstdio> # include <cstring> # include <cstdlib> # include <algorithm> # include <map> const int maxn1 = 3e4 + 5; const int maxn2 = 2e5 + 5; typedef long LL; using namespace std; int l [maxn2], r [maxn2], loc [maxn1], A [maxn1], id [maxn2], n; int C [maxn1], ans [maxn2]; inline int lowbit (int x) {return x &-x;} void update (int x, int d) {while (x <= n) {C [x] + = d; x + = lowbit (x) ;}} int Query (int x) {int sum = 0; while (X> 0) {sum + = C [x]; x-= lowbit (x);} return sum;} bool cmp (int I, int j) {return r [I] <r [j];} int main () {while (~ Scanf ("% d", & n) {memset (loc, 0, sizeof (loc); memset (C, 0, sizeof (C); map <int, int> q; q. clear (); for (int I = 1; I <= n; I ++) {scanf ("% d", A + I); update (I, 1 ); if (! Q [A [I]) {q [A [I] = I ;}} int m; scanf ("% d", & m ); for (int I = 1; I <= m; I ++) {scanf ("% d", l + I, r + I ); id [I] = I;} sort (id + 1, id + 1 + m, cmp ); /* The main idea is to drag the Count back as much as possible */int Right = 1; for (int I = 1; I <= m; ++ I) {int x = id [I]; while (Right <= r [x]) {if (q [A [Right]! = Right) {update (q [A [Right],-1);/* appears after, so that the previous count is offset and followed by the count, ensure that the number in the query interval is not omitted */q [A [Right] = Right ;}++ Right ;}right = r [x]; ans [x] = Query (r [x])-Query (l [x]-1);} for (int I = 1; I <= m; I ++) printf ("% d \ n", ans [I]);} return 0 ;}