这题跟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\n", query(T[r], l));}}return 0;
}