询问一段区间有多少个不同的数,用一个map维护数的位置,然后就是主席树基本应用。
#include <cstdio> #include <cstring> #include <algorithm> #include <map> using namespace std; const int maxn = 30010; int ls[maxn*20], rs[maxn*20], sum[maxn*20]; int T[maxn], tot; void build(int l, int r, int& rt) { rt = ++tot; sum[rt] = 0; if(l == r) return; int m = l+r>>1; build(l, m, ls[rt]); build(m+1, r, rs[rt]); } void update(int last, int p, int l, int r, int& rt, int num) { rt = ++tot; ls[rt] = ls[last]; rs[rt] = rs[last]; sum[rt] = sum[last] + num; if(l == r) return; int m = (l+r)>>1; if(p <= m) update(ls[last], p, l, m, ls[rt], num); else update(rs[last], p, m+1, r, rs[rt], num); } int query(int rt, int l, int r, int x, int y) { if(l == x && r == y) return sum[rt]; int m = (l+r) >> 1; int ans = 0; if(y <= m) ans += query(ls[rt], l, m, x, y); else if(x > m) ans += query(rs[rt], m+1, r, x, y); else ans += query(ls[rt], l, m, x, m)+query(rs[rt], m+1, r, m+1, y); return ans; } int num[maxn], a[maxn], n, q; void cal() { for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } build(1, n, T[0]); map<int, int> mp; for(int i = 1; i <= n; i++) { if(mp.find(a[i]) == mp.end()) { update(T[i-1], i, 1, n, T[i], 1); } else { update(T[i-1], mp[a[i]], 1, n, T[i], -1); update(T[i], i, 1, n, T[i], 1); } mp[a[i]] = i; } scanf("%d", &q); while(q--) { int x, y; scanf("%d %d", &x, &y); printf("%d\n", query(T[y], 1, n, x, y)); } } int main() { int T; while(scanf("%d", &n) != EOF) { tot = 0; cal(); } return 0; }