传送门php
给你一个长度为n的数列,其中有c种颜色,有q个询问,每一个询问问你在区间[l,r]中,有多少种颜色的个数大于2。c++
这个题目跟求区间内不一样的数的个数的解法很是类似。咱们在这题中一样采起离线树状数组的作法。数组
咱们发现,假若处于位置\(l\)的第\(i\)种颜色\(c_i\)要贡献答案,那么在位置\(l\)以后某个位置\(r\)必需要存在一个一样种类的颜色,那么在区间\([l,r]\)中颜色\(c_i\)就能贡献答案。那么咱们不妨记录一个数组\(nex[i]\),表明当前处于位置\(i\)的颜色\(c_i\)的下一个出现的位置。咱们发现以后的结点可否对答案进行贡献,取决于当前位置,所以咱们考虑从左到右更新树状数组。spa
咱们将询问的区间按照左端点排序,并从左到右进行遍历,假若遍历到位置\(i\),在以后还存在颜色\(c_i\),即\(nex[i]\)存在,那么咱们须要删除\(nex[i]\)的贡献;同时若是\(nex[nex[i]]\)存在,即证实在区间\([~nex[i]~,~nex[nex[i]]~]\)中,\(c_i\)可以贡献答案,故咱们须要增长\(nex[nex[i]]\)的贡献。code
每次更新完以后咱们只须要在树状数组中查询询问区间的个数便可。排序
// luogu-judger-enable-o2 #include <bits/stdc++.h> #define maxn 2000005 using namespace std; struct Node{ int l,r,pos; bool operator <(const Node &b)const{ if(l==b.l) return r<b.r; else return l<b.l; } }q[maxn]; int bit[maxn*2],a[maxn],mp[maxn],nex[maxn],ans[maxn]; int lowbit(int x){ return x&-x; } void update(int pos,int val){ for(int i=pos;i<maxn;i+=lowbit(i)){ bit[i]+=val; } } int query(int pos){ int res=0; for(int i=pos;i>0;i-=lowbit(i)){ res+=bit[i]; } return res; } int main() { int n,c,m; scanf("%d%d%d",&n,&c,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=n;i>=1;i--) { nex[i] = mp[a[i]]; mp[a[i]] = i; } for(int i=1;i<=c;i++){ if(mp[i]&&nex[mp[i]]){ update(nex[mp[i]],1); } } for(int i=1;i<=m;i++){ scanf("%d%d",&q[i].l,&q[i].r); q[i].pos=i; } sort(q+1,q+1+m); int pre=1; for(int i=1;i<=m;i++){ for(;pre<q[i].l;pre++){ if(nex[pre]) update(nex[pre],-1); if(nex[pre]&&nex[nex[pre]]) update(nex[nex[pre]],1); } ans[q[i].pos]=query(q[i].r)-query(q[i].l-1); } for(int i=1;i<=m;i++){ printf("%d\n",ans[i]); } return 0; }