NKOJ 3703 【莫队】HH的项链[SDOI2009]
思路:离线+动态更新+树状数组求前缀和
实现方法:
- 将输入数据按右边界排序。
- 从右边这小的开始向右边界大的依次回答,这样才能与我们便利和更新的顺序保持一致。
- 对于每一个询问,从上一个结束的位置开始,到这个区间遍历完,对于每一个数,如果这个数以前被更新过,就将以前打的标记清除,将现在的数打上标记。
- 把以 \(R_i\) 结尾的所有询问同一用当前更新好的值输出答案。
代码
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
int n;
int tree[1000005];
int arr[1000005];
int last[1000005];
int ans[1000005];
int lowbit(int x){return x&-x;}
struct qes{int l,r,id;}brr[1000005];
bool cmp(qes x,qes y){return x.r<y.r;}
void modify(int x,int y){for(int i=x;i<=1000000;i+=lowbit(i)) tree[i]+=y;}
int getsum(int x){int ans=0;for(int i=x;i>0;i-=lowbit(i)) ans+=tree[i];return ans;}
void update(int start,int end){
for(int j=start;j<=end;j++){
if(last[arr[j]]!=0) modify(last[arr[j]],-1);
last[arr[j]]=j;
modify(last[arr[j]],1);
}
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&arr[i]);
int q;
scanf("%lld",&q);
for(int i=1;i<=q;i++){
scanf("%lld%lld",&brr[i].l,&brr[i].r);
brr[i].id=i;
}
sort(brr+1,brr+1+q,cmp);
int s=1;
for(int i=1;i<=q;i++){
update(s,brr[i].r);
s=brr[i].r+1;
ans[brr[i].id]=getsum(brr[i].r)-getsum(brr[i].l-1);
}
for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
return 0;
}