[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\n", ans[i]);
} return 0;
}
原文地址:https://www.cnblogs.com/Nicoppa/p/11479310.html
时间: 2024-12-10 15:29:08