题目传送门
真是毒瘤题。
解法:
好恶心树状数组还有这个功能?!
区间种数也可以用树状数组维护?!
果断%一发题解。
看了半天发现:
用树状数组维护前缀和。
last[i]表示i这个位置的颜色上一个出现的位置是哪里。
那么我们在last[i]+1这个位置+1
在i+1这个位置-1。
那么我们在统计前缀和的时候每种颜色不论出现多少次贡献都为1。
每一段的答案等于求1~l的和。
为什么?
比如一个颜色在l之前有出现过,那么如果在l之后也出现了这种颜色的话,这种颜色一定是有1个贡献的。
如果一个颜色在l之前没有出现过,那么如果在l之后出现过了的话那么这种颜色的last=0,所以last+1也就是在1位置有+1所以颜色总类会+1。
自己yy吧这东西真毒瘤。
代码实现:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
struct node {
int l,r,s;
}a[210000];
bool cmp(node n1,node n2) {
return n1.r<n2.r;
}
int s[51000];
int lowbit(int x) {
return x&-x;
}
int n;
void change(int x,int k) {
while(x<=n) {
s[x]+=k;
x+=lowbit(x);
}
}
int get_sum(int x) {
int ans=0;
while(x>0) {
ans+=s[x];
x-=lowbit(x);
}
return ans;
}
int last[1110000],sh[1110000];
int ans[210000];
int main() {
int m;scanf("%d",&n);
for(int i=1;i<=n;i++) {
int x;scanf("%d",&x);
last[i]=sh[x];
sh[x]=i;
}
scanf("%d",&m);
for(int i=1;i<=m;i++) {
scanf("%d%d",&a[i].l,&a[i].r);
a[i].s=i;
}
sort(a+1,a+1+m,cmp);
int now=0;
for(int i=1;i<=m;i++) {
while(now<a[i].r) {
now++;
change(last[now]+1,1);
if(now!=n)
change(now+1,-1);
}
ans[a[i].s]=get_sum(a[i].l);
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}