题目链接
给出含有n个数字的序列,每次问区间[l,r]不同数的个数。
可以用主席树也可以用树状数组,做法都是同一个原理。从左往右扫一遍,记录每个数上一次出现的位置。当扫到i位置时,
把a[i]上一次出现的位置-1,i这个位置+1。然后对于所有询问区间[x, i]进行回答(BIT区间求和)。主席树也是这个原理,
只是要保存历史版本。
const int maxn = 3e4 + 123;
int ls[maxn*20], rs[maxn*20], root[maxn];
int sum[maxn*20];
int tot;
void build(int& rt, int l, int r) {
rt = ++ tot;
sum[rt] = 0;
if (l == r) return ;
int m = (l + r) >> 1;
build(ls[rt], l, m);
build(rs[rt], m + 1, r);
}
void updata(int last, int& rt, int l, int r, int pos, int val) {
rt = ++ tot;
sum[rt] = sum[last] + val;
ls[rt] = ls[last];
rs[rt] = rs[last];
if (l == r) {
// sum[rt] = val;
return ;
}
int m = (l + r) >> 1;
if (pos <= m) updata(ls[last], ls[rt], l, m, pos, val);
else updata(rs[last], rs[rt], m + 1, r, pos, val);
// sum[rt] = sum[ls[rt]] + sum[rs[rt]];
}
int find(int rt,int l, int r, int pos) {
int res = 0;
if (l == r) return sum[rt];
int m = (l + r) >> 1;
if (pos <= m) return find(ls[rt], l, m, pos);
return sum[ls[rt]] + find(rs[rt], m + 1, r, pos);
}
int a[maxn];
int main(int argc, const char * argv[])
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
// ios::sync_with_stdio(false);
// cout.sync_with_stdio(false);
// cin.sync_with_stdio(false);
int n;
while(~scanf("%d", &n)) {
tot = 0;
for (int i = 1;i <= n;++i) {
scanf("%d", &a[i]);
}
build(root[n + 1], 1, n);
map<int, int> mp;
for (int i = n;i >= 1;--i) {
if (mp.find(a[i]) == mp.end()) {
updata(root[i + 1], root[i], 1, n, i, 1);
}else {
int temp;
updata(root[i + 1], temp, 1, n, mp[a[i]], -1);//隔开中间这个历史版本
updata(temp, root[i], 1, n, i, 1);
}
mp[a[i]] = i;
}
int q;scanf("%d", &q);
while(q--) {
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", find(root[l], 1, n, r));
}
}
// showtime;
return 0;
}
/*
const int maxn = 1e6 + 10;
struct BIT {
int sum[maxn];
void init() {
memset(sum, 0, sizeof sum);
}
void add(int p, int v) {
while(p < maxn) {
sum[p] += v;
p += lowbit(p);
}
}
int find(int p) {
int res = 0;
while(p > 0) {
res += sum[p];
p -= lowbit(p);
}
return res;
}
}solve;
map<int, int> last;
vector > vec;
int a[maxn];
int n, m;
int ans[maxn];
int main(int argc, const char * argv[])
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
// ios::sync_with_stdio(false);
// cout.sync_with_stdio(false);
// cin.sync_with_stdio(false);
while(~scanf("%d", &n)) {
solve.init();
last.clear();
vec.clear();
vec.resize(maxn);
for (int i = 1;i <= n;++i) {
scanf("%d", &a[i]);
}
scanf("%d", &m);
for (int i = 1;i <= m;++i) {
int l, r;
scanf("%d%d", &l, &r);
vec[r].push_back(ii(l, i));
}
for (int i = 1;i <= n;++i) {
if (last[a[i]]) solve.add(last[a[i]], -1);
last[a[i]] = i;
solve.add(i, 1);
for (auto x : vec[i]) {
int idx = x.second;
int l = x.first;
ans[idx] = solve.find(i) - solve.find(l - 1);
// debug(idx);
}
}
for (int i = 1;i <= m;++i)
printf("%d\n", ans[i]);
}
// showtime;
return 0;
}
*/
/*
const int maxn =3e4 + 123;
int sum[maxn*20], ls[maxn*20], rs[maxn*20], root[maxn];
int a[maxn];
int tot;
int n;
void build(int& rt,int l, int r) {
rt = ++tot;
sum[rt] = 0;
if (l == r) return ;
int m = (l + r) >> 1;
build(ls[rt], l, m);
build(rs[rt], m + 1, r);
}
void updata(int last, int& rt,int l, int r, int pos, int val) {
rt = ++tot;
//从上一个线断树版本中复制数据
sum[rt] = sum[last] + val;
ls[rt] = ls[last];
rs[rt] = rs[last];
if (l == r) return ;
int m = (l + r) >> 1;
if (pos <= m) updata(ls[last], ls[rt], l, m, pos, val);
else updata(rs[last], rs[rt], m + 1, r, pos, val);
}
int find(int pos, int rt, int l, int r) {
if (l == r) return sum[rt];
int m = (l + r) >> 1;
if (pos <= m) return find(pos, ls[rt], l, m) + sum[rs[rt]];
return find(pos, rs[rt], m + 1, r);
}
int main(int argc, const char * argv[])
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
// ios::sync_with_stdio(false);
// cout.sync_with_stdio(false);
// cin.sync_with_stdio(false);
while(~scanf("%d", &n)) {
for (int i = 1;i <= n;++i)
scanf("%d", &a[i]);
map<int, int> mp;
build(root[0], 1, n);
for (int i = 1;i <= n;++i) {
if (mp.find(a[i]) == mp.end()) {
updata(root[i - 1], root[i], 1, n, i, 1);
}else {
int temp;
updata(root[i - 1], temp, 1, n, mp[a[i]], -1);
updata(temp, root[i], 1, n, i, 1);
}
mp[a[i]] = i;
}
int q;scanf("%d", &q);
while(q--) {
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", find(l, root[r], 1, n));
}
}
// showtime;
return 0;
}
*/