[luogu1972][SDOI2009]HH的项链
开始用莫队水了90分。
想了很久还是没想出来,于是看了一眼题解。妙!实在妙!
考虑一个数字只被算一次?那么其他的数应该被删掉。
对于一个固定的右区间端点,显然删的数越往后越好。
于是考虑把所有询问的区间按右端点排序,然后开始扫一遍。用树状数组维护前缀和。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lowbit(x) (x&(-x))
#define MAXN 500005
struct Node {
int l,r,num;
}G[MAXN];
int C[MAXN<<1],a[MAXN],book[MAXN<<1];
int ans[MAXN];
int N,M;
inline bool cmp(Node a,Node b) {
return a.r<b.r;
}
inline void update(int x,int u) {
for(;x<=N;x+=lowbit(x)) C[x] += u;
}
inline int query(int u) {
int ans = 0;
for(;u>=1;u-=lowbit(u)) ans += C[u];
return ans;
}
int main() {
std::memset(book,0,sizeof(book));
scanf("%d",&N);
for(int i=1;i<=N;++i) {
scanf("%d",&a[i]);
}
scanf("%d",&M);
for(int i=1;i<=M;++i) {
scanf("%d%d",&G[i].l,&G[i].r);
G[i].num = i;
}
std::sort(G+1,G+1+M,cmp);
int last = 0;
for(int i=1;i<=M;++i) {
for(;last+1<=G[i].r;) {
last++;
if(book[a[last]]) update(book[a[last]],-1);
book[a[last]] = last;
update(last,1);
}
ans[G[i].num] = query(G[i].r) - query(G[i].l-1);
}
for(int i=1;i<=M;++i) printf("%d\n",ans[i]);
return 0;
}