P1972 [SDOI2009]HH的项链
树状数组标记每个点在当前查询是否有贡献
需要离线,把查询区间的右端点升序排列,因为n=1e6,所有所有点只能遍历一次。对于每个数字,将它的贡献尽量给向后的点,当有贡献时该新位置树状数组值加1原位置-1,因为每个数字只能贡献一次,树状数组对区间查询。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
int c[maxn*4],a[maxn];
int n,q;
int lowbit(int x){
return x&(-x);
}
void update(int x,int v){
while(x<=n){
c[x]+=v;
x+=lowbit(x);
}
}
int query(int x){
int ans=0;
while(x>0){
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
struct ac{
int l,r,id,ans;
}ques[maxn];
int pre[maxn];
bool cmp1(ac a1,ac a2){
return a1.r<a2.r;
}
bool cmp2(ac a1,ac a2){
return a1.id<a2.id;
}
int main(){
memset(pre,0,sizeof pre);
n=read();
for(int i=1;i<=n;++i){
a[i]=read();
}
q=read();
for(int i=1;i<=q;++i){
ques[i].l=read();
ques[i].r=read();
ques[i].id=i;
}
sort(ques+1,ques+1+q,cmp1);
for(int i=1,j=1;i<=q;++i){
for(;j<=ques[i].r;++j){
update(j,1);
if(pre[a[j]]!=0)
update(pre[a[j]],-1);
pre[a[j]]=j;
}
ques[i].ans=query(ques[i].r)-query(ques[i].l-1);
}
sort(ques+1,ques+1+q,cmp2);
for(int i=1;i<=q;++i){
printf("%d\n",ques[i].ans);
}
}