这题跟HDU3333差不多吧。
离线的做法很简单,不再说了
以前做过。
主席树的做法就比较暴力了。。
什么是主席树呢。。
其实是某种称号。
在该题中的体现是可持久化的线段树。
对于一个数
如果以前没出现过
就插入到主席树中
否则就删除以前那个。
再插入主席树。
注意,所有的更新和删除都是建立了新的节点来保持其历史状态的。。
对于T[i]我们存的是从1到i区间的不同的数出现了多少个。
然后这棵树是根据T[i - 1]来建立的。
代码如下。。第一次写主席树。 几乎是照着爱将的代码写的。
不过他是倒着来插入的,我是正向来的。 无非是一个以左端点为根查询。一个以询问的右端点为根查询,
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <string> #include <map> #include <vector> #include <algorithm> #define INF 111111111 #define MAXN 33333 #define MAXM 600005 using namespace std; int n, tot, q, a[MAXN]; int T[MAXM], lson[MAXM], rson[MAXM], val[MAXM]; int nxt[MAXN], b[MAXN]; int build(int l, int r) { int rt = tot++; val[rt] = 0; int m = (l + r) >> 1; if(l != r) { lson[rt] = build(l, m); rson[rt] = build(m + 1, r); } return rt; } int update(int rt, int pos, int v) { int newrt = tot++, tmp = newrt; int l = 1, r = n; val[newrt] = val[rt] + v; while(l < r) { int m = (l + r) >> 1; if(pos <= m) { lson[newrt] = tot++; rson[newrt] = rson[rt]; newrt = lson[newrt]; rt = lson[rt]; r = m; } else { rson[newrt] = tot++; lson[newrt] = lson[rt]; newrt = rson[newrt]; rt = rson[rt]; l = m + 1; } val[newrt] = val[rt] + v; } return tmp; } int query(int rt, int pos) { int ret = 0; int l = 1, r = n; while(pos > l) { int m = (l + r) >> 1; if(pos <= m) { ret += val[rson[rt]]; rt = lson[rt]; r = m; } else { l = m + 1; rt = rson[rt]; } } return ret + val[rt]; } int main() { while(scanf("%d", &n) != EOF) { tot = 0; memset(nxt, -1, sizeof(nxt)); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); b[i - 1] = a[i]; } sort(b, b + n); int cnt = unique(b, b + n) - b; T[0] = build(1, n); for(int i = 1; i <= n; i++) { int id = lower_bound(b, b + cnt, a[i]) - b; if(nxt[id] == -1) T[i] = update(T[i - 1], i, 1); else { int t = update(T[i - 1], nxt[id], -1); T[i] = update(t, i, 1); } nxt[id] = i; } scanf("%d", &q); while(q--) { int l, r; scanf("%d%d", &l, &r); printf("%d ", query(T[r], l)); } } return 0; }