Skip to content

普通莫队 ​

cpp
namespace Mo{
    // 普通莫队
    struct Node{
        int id,l,r;
    };
    // be块编号,[L,R]块边界
    vector<int> be,L,R;
    // block块大小, tot块数量
    int block,tot;

    vector<Node> que; // 询问 
    bool cmp(Node x,Node y){
        return (be[x.l]^be[y.l])?be[x.l]<be[y.l]:((be[x.l]&1)?x.r<y.r:x.r>y.r);
        //奇数块从小到大,偶数块相反
    }
    void init(int n){
        block=sqrt(n);
        // block=max(1ll,sqrt(1.0*n*n/m));
        tot=(n+block-1)/block;
        be.assign(n+1,0);
        L.assign(tot+1,0);
        R.assign(tot+1,0);
        que.clear();
        for(int i=1;i<=tot;i++){
            L[i]=block*(i-1)+1,R[i]=min(block*i,n);
            for(int j=L[i];j<=R[i];j++)be[j]=i;
        }
    }
    void add_query(int l,int r){
        int id=que.size();
        que.push_back({id,l,r});
    }
}
using namespace Mo;
void solve(){
    int n,m;
    cin>>n;
    vector<int> w(n+1);
    int mx=0;
    for(int i=1;i<=n;i++)cin>>w[i],mx=max(mx,w[i]);
    cin>>m;
    init(n);
    for(int i=0;i<m;i++){
        int l,r;
        cin>>l>>r;
        add_query(l,r);
    }
    auto work=[&](){
        sort(que.begin(),que.end(),cmp);
        vector<int> ans(que.size());
        vector<int> cnt(mx+1);
        int res=0;
        auto add=[&](int x){
            if(!(cnt[w[x]]++))res++;
        };
        auto del=[&](int x){
            if(!(--cnt[w[x]]))res--;
        };
        int l=1,r=0;
        for(auto [id,ql,qr]:que){
            while(r<qr)add(++r);
            while(r>qr)del(r--);
            while(l<ql)del(l++);
            while(l>ql)add(--l);
            ans[id]=res;
        }
        return ans;
    };
    for(auto &x:work())cout<<x<<"\n";
}