bzoj 2742(樹狀數組)

傳送門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;
}
相關文章
相關標籤/搜索