[SDOI2009]HH的项链
原题链接 [SDOI2009]HH的项链
题目大意
给你 (n) 个数,再给你 (q) 次询问,每次询问给你 (l, r) ,问你 (l, r) 中有多少个不同的数
题目题解
分析这道题我们发现,对于一个 ([L_1, R_1]) 存在另一个 ([L_2, R_1]) 且 (L_2) 严格大于 (L_1),那么就一定存在第一个区间不同的数 大于等于 第二个区间的不同的数,这里很显然有一种等于的情况,什么情况等于?在([L_2,R_1]) 中包含的数与 ([L_1, L_2 - 1]) 中包含的数 ,后者的数前者都有。那么我们就发现 对于这样的情况([L_1, L_2 - 1]) 中就没有必要存在了。但注意的是,这里我们是严格定义的 (R_1)相同 且(L_1 < L_2),我们继续推发现(R_2 > R_1) 也是符合条件的。
于是我们得到若我们按查询的右区间从小到大排序,这样的就能转化为一个线性的前缀和问题,我们用数据结构来维护每一位上是否为1或0,若为1则说明之后没出现相同的数,若为1则说明出现过,每次处理到查询位的(R),然后用数据结构查询 (sum_R - sum_{l - 1}) 的值,就能得到我们的答案了
我们这里用树状数组维护,代码如下
//#define fre yes
#include <cstdio>
#include <algorithm>
const int N = 1000005;
struct Node {
int l, r;
int pos;
} w[N];
int Vis[N], arr[N], ans[N];
int tree[N];
bool cmp(Node x, Node y) {
return x.r < y.r;
}
int lowbit(int x) {
return x & (-x);
}
int n;
void change(int x, int k) {
while(x <= n) {
tree[x] += k;
x += lowbit(x);
}
}
int sum(int x) {
int res = 0;
while(x > 0) {
res += tree[x];
x -= lowbit(x);
} return res;
}
int main() {
static int q;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &arr[i]);
}
scanf("%d", &q);
for (int i = 1; i <= q; i++) {
int l, r;
scanf("%d %d", &l, &r);
w[i].l = l; w[i].r = r;
w[i].pos = i;
}
std::sort(w + 1, w + 1 + q, cmp);
int tot = 1;
for (int i = 1; i <= q; i++) {
for (int j = tot; j <= w[i].r; j++) {
if(Vis[arr[j]]) change(Vis[arr[j]], -1);
change(j, 1);
Vis[arr[j]] = j;
}
tot = w[i].r + 1;
ans[w[i].pos] = sum(w[i].r) - sum(w[i].l - 1);
}
for (int i = 1; i <= q; i++) {
printf("%d
", ans[i]);
} return 0;
}