[SDOI2009]HH的项链
题意:序列(n <= 1e6),有(m <= n)个询问,求(l)到(r)中有几个不相同的数。
题解:如果(n)的范围为(1e5)就是莫队裸题,但是由于(n)的范围为(1e6)那么就是可用树状数组操作,具体就是可发现,只有最后出现的数字有价值,设(r)指针从左到右,如果出现了一个数之前没出现过,在树状数组里此位置(+1),如果当前(r)的数出现过,那么就是之前的位置在树状数组中(-1),然后新的位置(+1),然后询问的话,就是(sum(r)-sum(l-1))就是区间([l,r])的不同数的数量
代码:
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 1000010, M = 1000010, S = 1000010;
ll lowbit(ll x) {
return -x&x;
}
int n;
struct BIT {
int d[N], Pos[N];
ll ask(ll pos) {ll ret = 0;while (pos>0) {ret += d[pos],pos -= lowbit(pos);}return ret;}
void add(ll pos, ll add){while (pos <= n)d[pos]+=add,pos+=lowbit(pos);}
}bit;
int a[N];
struct query {
int id,l, r;
}q[M];
ll ans[N];
bool cmp(query a, query b) {
return a.r < b.r;
}
signed main() {
scanf("%d",&n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
int m;scanf("%d", &m);
for (int i = 1; i <= m; i++) {
int l, r;
scanf("%d%d",&l,&r);
q[i] = {i, l, r};
}
sort(q + 1, q + 1 +m, cmp);
// for (int i = 1; i <= m; i++) {
// cout << q[i].l << " " << q[i].r << endl;
// }
for (int i = 1, j = 1; i <= m; i++) {
int id = q[i].id, l = q[i].l, r = q[i].r;
while ( j <= r ) {
int now = a[j];
//cout << "j:" << j << " " << "now:" << now << " " << bit.Pos[now] << endl;
if (bit.Pos[now] == 0) {
bit.add(j, 1);
//cout << "add" << j << " 1
";
bit.Pos[now] = j;
} else {
bit.add(bit.Pos[now], -1);
//cout << "add" << bit.Pos[now] << " " << -1 << endl;
//cout << "add" << j << " 1
";
bit.add(j, 1);
bit.Pos[now] = j;
}
//cout << bit.ask(j) << endl;
j++;
}
//cout << l << "->" << r << endl;
// for (int ii = 0; ii <= n; ii++) {
// cout <<"ii:" << ii << " " << bit.ask(ii) << endl;
// }
ans[id] = bit.ask(r) - bit.ask(l-1);
// cout << "ans" << " " << ans[id] << endl;
}
for (int i =1; i <= m; i++) {
printf("%d
", ans[i]);
}
return 0;
}