如果能够把所有区间内第二次出现某颜色的位置标记出来,树状数组查询一下就可以了。
考虑离线。按左端点从小到大排序,不断移动左端点并更新第二次出现的位置。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 2000010 int n,m,c,a[N],nxt[N],p[N],tree[N],ans[N],flag[N]; struct data { int l,r,i; bool operator <(const data&a) const { return l<a.l; } }q[N]; void add(int k,int x){while (k<=n) tree[k]+=x,k+=k&-k;} int sum(int k){int s=0;while (k) s+=tree[k],k-=k&-k;return s;} int main() { #ifndef ONLINE_JUDGE freopen("bzoj2743.in","r",stdin); freopen("bzoj2743.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(),c=read(),m=read(); for (int i=1;i<=n;i++) { a[i]=read(),nxt[p[a[i]]]=i,p[a[i]]=i; if (flag[a[i]]==1) add(i,1),flag[a[i]]=2; else if (!flag[a[i]]) flag[a[i]]=1; } for (int i=1;i<=n+1;i++) if (!nxt[i]) nxt[i]=n+1; for (int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].i=i; sort(q+1,q+m+1); q[0].l=1; for (int i=1;i<=m;i++) { while (q[i].l>q[i-1].l) add(nxt[q[i-1].l],-1),add(nxt[nxt[q[i-1].l]],1),q[i-1].l++; ans[q[i].i]=sum(q[i].r)-sum(q[i].l-1); } for (int i=1;i<=m;i++) printf("%d ",ans[i]); return 0; }