【题解】[洛谷 P4396 / bzoj 3236] 作业【莫队 分块 根号平衡】

题目链接

题目链接

题意

给定序列 (a),多次询问:

  • (a[l..r]) 有多少数在 ([a..b]) 中;
  • (a[l..r]) 有多少数在 ([a..b]) 中(去重)。

(n,mleq 10^5)

题解

莫队显然。每次移动指针时要单点修改((O(nsqrt n)) 次),查询时查询区间和((O(n)) 次)。用分块实现 (O(1)) 修改、(O(sqrt n)) 查询,复杂度为 (O(nsqrt n))

#include<bits/stdc++.h>
using namespace std;

const int BUF_LEN=1<<19;
struct FastIO{
    char bufi[BUF_LEN+10],*PTi=bufi+BUF_LEN,*PTENDi=bufi+BUF_LEN;
    inline char gc(){
        (PTi==PTENDi)&&(bufi[fread(bufi,1,BUF_LEN,stdin)]=0,PTi=bufi);
        return *(PTi++);
    }
    char bufo[BUF_LEN+10],*PTo=bufo,*PTENDo=bufo+BUF_LEN;
    inline void pc(char c){
        (PTo==PTENDo)&&(fwrite(bufo,1,BUF_LEN,stdout),PTo=bufo);
        *(PTo++)=c;
    }
    void flush(){
        fwrite(bufo,1,PTo-bufo,stdout);
        PTo=bufo;
    }
    ~FastIO(){
        flush();
    }

    template<class T>inline void getint(T &x=0){
        char c=gc();
        int f=1;x=0;
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;
            c=gc();
        }
        while(c>='0'&&c<='9'){
            x=x*10+c-'0'; 
            c=gc();
        }
        if(f==-1)x=-x;
    }
    operator int(){
        int v;getint(v);return v;
    }
    operator long long(){
        long long v;getint(v);return v;
    }
    template<class T>inline void putint(T x=0,char sep=' '){
        char tmp[20],len=0;
        if(x<0)pc('-'),x=-x;
        if(x==0){ pc('0');pc(sep);return; }
        while(x)tmp[len++]=x%10,x/=10;
        for(int i=len-1;~i;--i)pc(tmp[i]|'0');
        pc(sep);
    }
}io;

const int N=1e5+10,M=1e6+10,Q=1010;
struct Block_div{
    int blk;
    int s[Q],a[N];
    void modify(int x,int y){ s[x/blk]+=y,a[x]+=y; }
    int query(int r){
        int ans=0;
        int i=blk-1;
        for(int j=0;i<=r;i+=blk,j++)ans+=s[j];
        for(i-=blk-1;i<=r;i++)ans+=a[i];
        return ans;
    }
};
Block_div s,uni;

int n,m;
int a[N];
int blk,bl[N];
struct Query{
    int l,r,a,b,num;
}q[M];
bool cmp(const Query &a,const Query &b){
    return bl[a.l]^bl[b.l]?bl[a.l]<bl[b.l]:bl[a.l]&1?a.r<b.r:a.r>b.r;
}
int ans1[M],ans2[M];

int main(){
    n=io,m=io;
    blk=max(n/sqrt(m*0.8),1.0);
    s.blk=uni.blk=sqrt(n);
    for(int i=1;i<=n;i++)a[i]=io;

    for(int i=1;i<=n;i++)bl[i]=i/blk;
    for(int i=0;i<m;i++)q[i].l=io,q[i].r=io,q[i].a=io,q[i].b=io,q[i].num=i;
    sort(q,q+m,cmp);
    
    int l=2,r=1;
    for(int i=0;i<m;i++){
        while(l<q[i].l){
            s.modify(a[l],-1);
            if(!s.a[a[l]])uni.modify(a[l],-1);
            ++l;
        }
        while(r>q[i].r){
            s.modify(a[r],-1);
            if(!s.a[a[r]])uni.modify(a[r],-1);
            --r;
        }
        while(l>q[i].l){
            --l;
            if(!s.a[a[l]])uni.modify(a[l],1);
            s.modify(a[l],1);
        }
        while(r<q[i].r){
            ++r;
            if(!s.a[a[r]])uni.modify(a[r],1);
            s.modify(a[r],1);
        }
        ans1[q[i].num]=s.query(q[i].b)-s.query(q[i].a-1);
        ans2[q[i].num]=uni.query(q[i].b)-uni.query(q[i].a-1);
    }
    for(int i=0;i<m;i++)io.putint(ans1[i],' '),io.putint(ans2[i],'
');
}

原文地址:https://www.cnblogs.com/wallbreaker5th/p/14251799.html