链接:Miku
--------------------------
%%%ljx巨佬会莫队
-------------------------
这道题可以用树状数组过
-------------------------
首先,把所有询问按照右端点从小到大排序,这个很容易想到,然后非常容易想到,建立一个数组f,
如果数字a在i出现了,就再f[i]=1,然后统计一下区间和就可以了,当然,用树状数组优化
------------------------
然而考虑一下这样的问题:区间不包含这个数了,这个数重复了
这个问题解决方法就是建立一个数组fl,记录这个数上一次出现的位置,然后对于每一个数,只保留最右边的那个就可以了
----------------------------
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m; int a[1000005]; struct qu{ int l; int r; int num; }qj[1000005]; int fl[1000005]; bool cmp(qu x,qu y){ return x.r<y.r; } int tree[1000005]; int ans[1000005]; int lowbit(int x){ return x&-x; } void add(int x,int k){ while(x<=n){ tree[x]+=k; x+=lowbit(x); } return ; } int sum(int x){ int ans=0; while(x){ ans+=tree[x]; x-=lowbit(x); } return ans; } int main(){ 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",&qj[i].l,&qj[i].r); qj[i].num=i; } sort(qj+1,qj+m+1,cmp); int r = 1; for(int i=1;i<=m;++i){ while (r <= qj[i].r){//统计时间 add(r, 1);//先加上 if (fl[a[r]] != 0){//去重 add(fl[a[r]], -1); } fl[a[r]] = r;//重新记录上一次出现的位置 r++; } ans[qj[i].num] = sum(qj[i].r) - sum(qj[i].l - 1); } for (int i = 1; i <= m; i++) printf("%d ", ans[i]); return 0; }