传送门
题目描述:多次询问一个区间内不同数的数量。
解题思路:一个区间内存在相同的数,所以我们的线段树就不能维护数,应该去维护下标?为什么去维护下标呢,就算一个数相同,但是它们的下标肯定是不同的,我们的线段树维护下标存在的情况。
如果区间内存在重复的数,意味着不同下标对应相同的数,如果我们记录多个下标答案就会重复,我们要怎么去解决这个问题呢?
我们把下标右移(相同的数,我们记录的下标只记录最右边的那一个)。因为如果这个数出现过,为了维护这个状态的线段树,就应该记录下当前的这个下标,取消以前的标记。
我们查询答案时,只需要查询在 r 时刻状态的线段中在 [ l , r ] 区间内下标存在的个数就是答案。
细节请看代码:
///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a, b) memset(a,b,sizeof(a));
#define lowbit(x) (x&(-x));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai = acos(-1.0);
const double E = 2.718281828459;
const ll mod = 20071027;
const ll INF = 0x3f3f3f3f3f3f;
const int maxn = 3e4 + 5;
struct node {
int ls, rs, cnt;
} p[maxn * 40];
int root[maxn], times;
int pos[1000005];
void insert(int &now, int old, int l, int r, int sub, int x) {
now = ++times;
p[now] = p[old], p[now].cnt += x;
if (l == r) return;
int mid = (l + r) >> 1;
if (sub <= mid) insert(p[now].ls, p[old].ls, l, mid, sub, x);
else insert(p[now].rs, p[old].rs, mid + 1, r, sub, x);
}
int query(int now, int l, int r, int a, int b) {
if (l == a && r == b) return p[now].cnt;
int mid = (l + r) >> 1;
if (b <= mid) return query(p[now].ls, l, mid, a, b);
else if (a > mid) return query(p[now].rs, mid + 1, r, a, b);
else return query(p[now].ls, l, mid, a, mid) + query(p[now].rs, mid + 1, r, mid + 1, b);
}
void init() {
times = 0;
memset(p, 0, sizeof(p));
memset(root, 0, sizeof(root));
memset(pos, 0, sizeof(pos));
}
int main() {
init();
int n, op, x, l, r;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
if (pos[x]) {
insert(root[i], root[i - 1], 1, n, i, 1);
insert(root[i], root[i], 1, n, pos[x], -1);
} else
insert(root[i], root[i - 1], 1, n, i, 1);
pos[x] = i;
}
scanf("%d", &op);
while (op--) {
scanf("%d %d", &l, &r);
printf("%d\n", query(root[r], 1, n, l, r));
}
}