傳送門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; }