分块大法好

新手推荐阅读:「分块」数列分块入门1 – 9 by hzwer

练习:LibreOJ


 “大段维护,局部朴素”

分块的调试检测技巧:

可以生成一些大数据,然后用两份分块大小不同的代码来对拍,还可以根据运行时间尝试调整分块大小,减小常数。

 

区间加法,单点查询

 1 #include<bits/stdc++.h>
 2 #define IL inline
 3 #define R register int
 4 #define ls(x) a[x].ch[0]
 5 #define rs(x) a[x].ch[1]
 6 #define fa(x) a[x].fa
 7 
 8 using namespace std;
 9 const int N=1e5+5,inf=0x3f3f3f3f;
10 
11 IL int read() {
12     int f=1;char ch;
13     while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
14     int res=ch-'0';
15     while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
16     return res*f;
17 }
18 
19 int n,a[N],ad[N],b[N],len;
20 
21 IL void pre() {
22     len=sqrt(n);
23     for(R i=1;i<=n;++i) b[i]=(i-1)/len+1;
24 }
25 
26 IL void add(int l,int r,int c) {
27     for(R i=l;i<=min(r,b[l]*len);++i) a[i]+=c;
28     if(b[l]!=b[r]) for(R i=(b[r]-1)*len+1;i<=r;++i) a[i]+=c;
29     for(R i=b[l]+1;i<=b[r]-1;++i) ad[i]+=c;
30 }
31 
32 IL void query(int x) {
33     printf("%d
",a[x]+ad[b[x]]);
34 }
35 
36 int main() {
37     n=read();
38     for(R i=1;i<=n;++i) a[i]=read();
39     pre();
40     for(R i=1;i<=n;++i) {
41         int op=read(),l=read(),r=read(),c=read();
42         if(!op) add(l,r,c);
43         else query(r);
44     }
45     return 0;    
46 }
分块1

 

区间加法,询问区间内小于某个值x的元素个数

//vector

 1 #include<bits/stdc++.h>
 2 #define IL inline
 3 #define R register int
 4 #define ls(x) a[x].ch[0]
 5 #define rs(x) a[x].ch[1]
 6 #define fa(x) a[x].fa
 7 
 8 using namespace std;
 9 const int N=1e5+5,inf=0x3f3f3f3f;
10 
11 IL int read() {
12     int f=1;char ch;
13     while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
14     int res=ch-'0';
15     while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
16     return res*f;
17 }
18 
19 int n,a[N],ad[N],b[N],len;
20 vector<int> s[N];
21 
22 IL void pre() {
23     len=sqrt(n);
24     for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,s[b[i]].push_back(a[i]);
25     for(R i=1;i<=b[n];++i)sort(s[i].begin(),s[i].end());
26 }
27 
28 IL void reset(int x) {
29     s[x].clear();
30     for(R i=(x-1)*len+1;i<=min(x*len,n);++i) s[x].push_back(a[i]);
31     sort(s[x].begin(),s[x].end());
32 }
33 
34 IL void add(int l,int r,int c) {
35     for(R i=l;i<=min(r,b[l]*len);++i) a[i]+=c;reset(b[l]);
36     if(b[l]!=b[r]) {
37         for(R i=(b[r]-1)*len+1;i<=r;++i) a[i]+=c;
38         reset(b[r]);
39     }
40     for(R i=b[l]+1;i<=b[r]-1;++i) ad[i]+=c;
41 }
42 
43 IL void query(int l,int r,int x) {
44     int ans=0;
45     for(R i=l;i<=min(r,b[l]*len);++i) 
46         if(a[i]+ad[b[i]]<x) ans++;
47     if(b[l]!=b[r]) 
48         for(R i=(b[r]-1)*len+1;i<=r;++i) 
49             if(a[i]+ad[b[i]]<x) ans++;
50     for(R i=b[l]+1;i<=b[r]-1;++i) ans+=lower_bound(s[i].begin(),s[i].end(),x-ad[i])-s[i].begin();
51     printf("%d
",ans);
52 }
53 
54 int main() {
55     n=read();
56     for(R i=1;i<=n;++i) a[i]=read();
57     pre();
58     for(R i=1;i<=n;++i) {
59         int op=read(),l=read(),r=read(),c=read();
60         if(!op) add(l,r,c);
61         else query(l,r,c*c);
62     }
63     return 0;    
64 }
分块2

 

区间加法,询问区间内小于某个值x的前驱(比其小的最大元素)

//set

 1 #include<bits/stdc++.h>
 2 #define IL inline
 3 #define R register int
 4 #define ls(x) a[x].ch[0]
 5 #define rs(x) a[x].ch[1]
 6 #define fa(x) a[x].fa
 7 
 8 using namespace std;
 9 const int N=1e5+5,inf=0x3f3f3f3f;
10 
11 IL int read() {
12     int f=1;char ch;
13     while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
14     int res=ch-'0';
15     while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
16     return res*f;
17 }
18 
19 int n,a[N],ad[N],b[N],len;
20 set<int> s[N];
21 
22 IL void pre() {
23     len=1000;
24     for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,s[b[i]].insert(a[i]);
25 }
26 
27 IL void add(int l,int r,int c) {
28     for(R i=l;i<=min(r,b[l]*len);++i) {
29         s[b[i]].erase(a[i]);
30         a[i]+=c;
31         s[b[i]].insert(a[i]);
32     }
33     if(b[l]!=b[r]) 
34         for(R i=(b[r]-1)*len+1;i<=r;++i) {
35             s[b[i]].erase(a[i]);
36             a[i]+=c;
37             s[b[i]].insert(a[i]);
38         }
39     for(R i=b[l]+1;i<=b[r]-1;++i) ad[i]+=c;
40 }
41 
42 IL void query(int l,int r,int x) {
43     int ans=-1;
44     for(R i=l;i<=min(r,b[l]*len);++i) 
45         if(a[i]+ad[b[i]]<x) ans=max(ans,a[i]+ad[b[i]]);
46     if(b[l]!=b[r]) 
47         for(R i=(b[r]-1)*len+1;i<=r;++i) 
48             if(a[i]+ad[b[i]]<x) ans=max(ans,a[i]+ad[b[i]]);
49     for(R i=b[l]+1;i<=b[r]-1;++i) {
50         set<int>::iterator it=s[i].lower_bound(x-ad[i]);
51         if(it==s[i].begin()) continue;
52         --it;ans=max(ans,*it+ad[i]);
53     }
54     printf("%d
",ans);
55 }
56 
57 int main() {
58     n=read();
59     for(R i=1;i<=n;++i) a[i]=read();
60     pre();
61     for(R i=1;i<=n;++i) {
62         int op=read(),l=read(),r=read(),c=read();
63         if(!op) add(l,r,c);
64         else query(l,r,c);
65     }
66     return 0;    
67 }
分块3

 

区间加法,区间求和

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define IL inline
 4 #define R register int
 5 #define ls(x) a[x].ch[0]
 6 #define rs(x) a[x].ch[1]
 7 #define fa(x) a[x].fa
 8 
 9 using namespace std;
10 const int N=1e5+5,inf=0x3f3f3f3f;
11 
12 IL int read() {
13     int f=1;char ch;
14     while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
15     int res=ch-'0';
16     while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
17     return res*f;
18 }
19 
20 int n,a[N],ad[N],b[N],len,sum[N];
21 
22 IL void pre() {
23     len=sqrt(n);
24     for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,sum[b[i]]+=a[i];
25 }
26 
27 IL void add(int l,int r,int c) {
28     for(R i=l;i<=min(r,b[l]*len);++i) 
29         a[i]+=c,sum[b[i]]+=c;
30     if(b[l]!=b[r]) 
31         for(R i=(b[r]-1)*len+1;i<=r;++i) 
32             a[i]+=c,sum[b[i]]+=c;
33     for(R i=b[l]+1;i<=b[r]-1;++i) ad[i]+=c;
34 }
35 
36 IL void query(int l,int r,int x) {
37     int ans=0;
38     for(R i=l;i<=min(r,b[l]*len);++i) 
39         ans+=a[i]+ad[b[i]];
40     if(b[l]!=b[r]) 
41         for(R i=(b[r]-1)*len+1;i<=r;++i) 
42             ans+=a[i]+ad[b[i]];
43     for(R i=b[l]+1;i<=b[r]-1;++i) {
44         ans+=sum[i]+ad[i]*len;
45     }
46     printf("%lld
",ans%(x+1));
47 }
48 
49 signed main() {
50     n=read();
51     for(R i=1;i<=n;++i) a[i]=read();
52     pre();
53     for(R i=1;i<=n;++i) {
54         int op=read(),l=read(),r=read(),c=read();
55         if(!op) add(l,r,c);
56         else query(l,r,c);
57     }
58     return 0;    
59 }
分块4

 

区间开方,区间求和

//跳过已经不能再开方(元素值为0或1)的块

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define IL inline
 4 #define R register int
 5 #define ls(x) a[x].ch[0]
 6 #define rs(x) a[x].ch[1]
 7 #define fa(x) a[x].fa
 8 
 9 using namespace std;
10 const int N=1e5+5,inf=0x3f3f3f3f;
11 
12 IL int read() {
13     int f=1;char ch;
14     while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
15     int res=ch-'0';
16     while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
17     return res*f;
18 }
19 
20 int n,a[N],b[N],len,sum[N],flag[N];
21 
22 IL void pre() {
23     len=sqrt(n);
24     for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,sum[b[i]]+=a[i];
25 }
26 
27 IL void allsqrt(int x) {
28     if(flag[x]) return ;
29     flag[x]=1;
30     sum[x]=0;
31     for(R i=(x-1)*len+1;i<=x*len;++i) {
32         a[i]=sqrt(a[i]);sum[x]+=a[i];
33         if(a[i]>1) flag[x]=0;
34     }
35 }
36 
37 IL void work(int l,int r,int c) {
38     for(R i=l;i<=min(r,b[l]*len);++i) 
39         sum[b[i]]-=a[i],a[i]=sqrt(a[i]),sum[b[i]]+=a[i];
40     if(b[l]!=b[r]) 
41         for(R i=(b[r]-1)*len+1;i<=r;++i) 
42             sum[b[i]]-=a[i],a[i]=sqrt(a[i]),sum[b[i]]+=a[i];
43     for(R i=b[l]+1;i<=b[r]-1;++i) allsqrt(i);
44 }
45 
46 IL void query(int l,int r,int x) {
47     int ans=0;
48     for(R i=l;i<=min(r,b[l]*len);++i) 
49         ans+=a[i];
50     if(b[l]!=b[r]) 
51         for(R i=(b[r]-1)*len+1;i<=r;++i) 
52             ans+=a[i];
53     for(R i=b[l]+1;i<=b[r]-1;++i) {
54         ans+=sum[i];
55     }
56     printf("%lld
",ans);
57 }
58 
59 signed main() {
60     n=read();
61     for(R i=1;i<=n;++i) a[i]=read();
62     pre();
63     for(R i=1;i<=n;++i) {
64         int op=read(),l=read(),r=read(),c=read();
65         if(!op) work(l,r,c);
66         else query(l,r,c);
67     }
68     return 0;    
69 }
分块5

应用:洛谷P4145 上帝造题的七分钟2 / 花神游历各国

#include<bits/stdc++.h>
#define int long long
#define IL inline
#define R register int
#define ls(x) a[x].ch[0]
#define rs(x) a[x].ch[1]
#define fa(x) a[x].fa

using namespace std;
const int N=1e5+5,inf=0x3f3f3f3f;

IL int read() {
    int f=1;char ch;
    while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    int res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
    return res*f;
}

int n,a[N],b[N],len,sum[N],flag[N];

IL void pre() {
    len=sqrt(n);
    for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,sum[b[i]]+=a[i];
}

IL void allsqrt(int x) {
    if(flag[x]) return ;
    flag[x]=1;
    sum[x]=0;
    for(R i=(x-1)*len+1;i<=x*len;++i) {
        a[i]=sqrt(a[i]);sum[x]+=a[i];
        if(a[i]>1) flag[x]=0;
    }
}

IL void work(int l,int r) {
    for(R i=l;i<=min(r,b[l]*len);++i) 
        sum[b[i]]-=a[i],a[i]=sqrt(a[i]),sum[b[i]]+=a[i];
    if(b[l]!=b[r]) 
        for(R i=(b[r]-1)*len+1;i<=r;++i) 
            sum[b[i]]-=a[i],a[i]=sqrt(a[i]),sum[b[i]]+=a[i];
    for(R i=b[l]+1;i<=b[r]-1;++i) allsqrt(i);
}

IL void query(int l,int r) {
    int ans=0;
    for(R i=l;i<=min(r,b[l]*len);++i) 
        ans+=a[i];
    if(b[l]!=b[r]) 
        for(R i=(b[r]-1)*len+1;i<=r;++i) 
            ans+=a[i];
    for(R i=b[l]+1;i<=b[r]-1;++i) {
        ans+=sum[i];
    }
    printf("%lld
",ans);
}

signed main() {
    n=read();
    for(R i=1;i<=n;++i) a[i]=read();
    int m=read();
    pre();
    for(R i=1;i<=m;++i) {
        int op=read(),l=read(),r=read();
        if(l>r) swap(l,r);
        if(!op) work(l,r);
    else query(l,r);
    }
    return 0;    
}
P4145代码

 

单点插入,单点询问

//vector自带insert、重新分块(重构)

#include<bits/stdc++.h>
#define int long long
#define IL inline
#define R register int
#define PII pair<int,int>
#define fi first
#define se second
#define mk make_pair

using namespace std;
const int N=5e5+5,inf=0x3f3f3f3f;

IL int read() {
    int f=1;char ch;
    while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    int res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
    return res*f;
}

int n,a[N],len,st[N],m,b[N];
vector<int> s[N];

IL void pre() {
    len=sqrt(n);m=n;
    for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,s[b[i]].push_back(a[i]);
}

IL PII find(int x) {
    int i=1;
    while(x>s[i].size()) x-=s[i].size(),i++;//x belongs to s[i]
    return mk(i,x-1);
}

IL void rebuild() {
    int top=0;
    for(R i=1;i<=b[m];++i) {
        for(R j=0;j<s[i].size();++j) st[++top]=s[i][j];
        s[i].clear();
    }
    len=sqrt(n);
    for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,s[b[i]].push_back(st[i]);
}

IL void insert(int l,int r) {
    PII t=find(l);
    s[t.fi].insert(s[t.fi].begin()+t.se,r);
    if(s[t.fi].size()>20*len) rebuild();
}

IL void query(int r) {
    PII t=find(r);
    printf("%lld
",s[t.fi][t.se]);
}

signed main() {
    m=n=read();
    for(R i=1;i<=n;++i) a[i]=read();
    pre();
    for(R i=1;i<=m;++i) {
        int op=read(),l=read(),r=read(),c=read();
        if(!op) insert(l,r),++n;
        else query(r);
    }
    return 0;
}
分块6

 

区间乘法,区间加法,单点询问

//先乘后加

#include<bits/stdc++.h>
#define int long long
#define IL inline
#define R register int

using namespace std;
const int N=1e5+5,inf=0x3f3f3f3f,mod=10007;

IL int read() {
    int f=1;
    char ch;
    while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    int res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
    return res*f;
}

int n,a[N],b[N],len,ad[N],mul[N];

IL void pre() {
    len=sqrt(n);
    for(R i=1; i<=n; ++i) b[i]=(i-1)/len+1,mul[b[i]]=1;
}

void reset(int x) {
    for(R i=(x-1)*len+1; i<=min(n,x*len); ++i)
        a[i]=a[i]*mul[x]%mod,a[i]=(a[i]+ad[x])%mod;
    mul[x]=1;ad[x]=0;
}

IL void work(int op,int l,int r,int c) {
    reset(b[l]);
    for(R i=l; i<=min(r,b[l]*len); ++i)
        if(op) a[i]=a[i]*c%mod;
        else a[i]=(a[i]+c)%mod;
    if(b[l]!=b[r]) {
        reset(b[r]);
        for(R i=(b[r]-1)*len+1; i<=r; ++i)
            if(op) a[i]=a[i]*c%mod;
            else a[i]=(a[i]+c)%mod;
    }
    for(R i=b[l]+1; i<=b[r]-1; ++i)
        if(op) mul[i]=mul[i]*c%mod,ad[i]=ad[i]*c%mod;
        else ad[i]=(ad[i]+c)%mod;
}

IL void query(int i) {
    int x=b[i];
    //a[i]=a[i]*mul[x]%mod,a[i]=(a[i]+ad[x])%mod;
    printf("%lld
",(a[i]*mul[x]%mod+ad[x])%mod);
}

signed main() {
    n=read();
    for(R i=1; i<=n; ++i) a[i]=read();
    pre();
    for(R i=1; i<=n; ++i) {
        int op=read(),l=read(),r=read(),c=read();
        if(op==2) query(r);
        else work(op,l,r,c);
    }
    return 0;
}
分块7

应用:P3373 【模板】线段树 2

//线段树模板也可以用分块来做~吸个氧还是能卡过去的

#include<bits/stdc++.h>
#define int long long
#define IL inline
#define R register int

using namespace std;
const int N=1e5+5,inf=0x3f3f3f3f;

IL int read() {
    int f=1;
    char ch;
    while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    int res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
    return res*f;
}

int n,a[N],b[N],len,ad[N],mul[N],m,p,sum[N];

IL int mod(int x) {return x>p?x-p:x;}

IL void pre() {
    len=sqrt(n);
    for(R i=1; i<=n; ++i) b[i]=(i-1)/len+1,mul[b[i]]=1,sum[b[i]]+=a[i];
}

void reset(int x) {
    sum[x]=0;
    for(R i=(x-1)*len+1; i<=min(n,x*len); ++i)
        a[i]=(a[i]*mul[x]+ad[x])%p,sum[x]=mod(sum[x]+a[i]);
    mul[x]=1;ad[x]=0;
}

IL void work(int op,int l,int r,int c) {
    reset(b[l]);
    for(R i=l; i<=min(r,b[l]*len); ++i)
        if(op==1) sum[b[l]]+=(c-1)*a[i]%p,a[i]=a[i]*c%p;
        else sum[b[l]]=mod(sum[b[l]]+c),a[i]=mod(a[i]+c);
    if(b[l]!=b[r]) {
        reset(b[r]);
        for(R i=(b[r]-1)*len+1; i<=r; ++i)
            if(op==1) sum[b[r]]+=(c-1)*a[i]%p,a[i]=a[i]*c%p;
            else sum[b[r]]=mod(sum[b[r]]+c),a[i]=mod(a[i]+c);
    }
    for(R i=b[l]+1; i<=b[r]-1; ++i)
        if(op==1) mul[i]=mul[i]*c%p,ad[i]=ad[i]*c%p;
        else ad[i]=mod(ad[i]+c);
}

IL void query(int l,int r) {
    int ans=0;
    reset(b[l]);
    for(R i=l; i<=min(r,b[l]*len); ++i) ans=mod(ans+a[i]);
    if(b[l]!=b[r]) {
        reset(b[r]);
        for(R i=(b[r]-1)*len+1; i<=r; ++i) ans=mod(ans+a[i]);
    }
    for(R i=b[l]+1;i<=b[r]-1;++i) ans=mod(ans+mod(sum[i]*mul[i]%p+ad[i]*len%p));
    printf("%lld
",ans);
}

signed main() {
    n=read(),m=read(),p=read();
    for(R i=1; i<=n; ++i) a[i]=read();
    pre();
    for(R i=1; i<=m; ++i) {
        int op=read(),l=read(),r=read();
        if(op==3) query(l,r);
        else {
            int c=read();
            work(op,l,r,c);
        }
    }
    return 0;
}
P3373代码

 

区间询问等于一个数c的元素,并将这个区间的所有元素改为c

#include<bits/stdc++.h>
#define int long long
#define IL inline
#define R register int

using namespace std;
const int N=1e5+5,inf=0x3f3f3f3f;

IL int read() {
    int f=1;
    char ch;
    while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    int res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
    return res*f;
}

int n,a[N],b[N],len,tag[N];

IL void pre() {
    len=sqrt(n);
    for(R i=1; i<=n; ++i) b[i]=(i-1)/len+1,tag[i]=-1;;
}

void reset(int x) {
    if(tag[x]==-1) return ;
    for(R i=(x-1)*len+1;i<=x*len;++i) a[i]=tag[x];
    tag[x]=-1;
}

IL void query(int l,int r,int c) {
    int ans=0;
    reset(b[l]);
    for(R i=l; i<=min(r,b[l]*len); ++i) 
        if(a[i]!=c) a[i]=c;
        else ans++;
    if(b[l]!=b[r]) {
        reset(b[r]);
        for(R i=(b[r]-1)*len+1; i<=r; ++i) 
            if(a[i]!=c) a[i]=c;
            else ans++;
    }
    for(R i=b[l]+1;i<=b[r]-1;++i) 
        if(tag[i]==-1) {
            for(R j=(i-1)*len+1;j<=i*len;++j) 
                if(a[j]!=c) a[j]=c;
                else ans++;
            tag[i]=c;
        }
        else {
            if(tag[i]==c) ans+=len;
            else tag[i]=c;
        }
    printf("%lld
",ans);
}

signed main() {
    n=read();
    for(R i=1; i<=n; ++i) a[i]=read();
    pre();
    for(R i=1; i<=n; ++i) {
        int l=read(),r=read(),c=read();
        query(l,r,c);
    }
    return 0;
}
分块8

 

询问区间的最小众数

预处理保存以“段边界”为端点的区间[L,R]的众数。另外,对每个数值建立一个STL vector,按顺序保存该数值在序列a中每次出现的位置。

对于每个询问,扫描[l,L)与(R,r]中的每个数x,在对应的vector里二分查找即可得到x在[l,r]中出现的次数,从而更新答案。

——《算法竞赛进阶指南》

#include<bits/stdc++.h>
#define int long long
#define IL inline
#define R register int

using namespace std;
const int N=1e5+5,inf=0x3f3f3f3f;

IL int read() {
    int f=1;
    char ch;
    while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    int res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
    return res*f;
}

int n,a[N],b[N],len,f[1505][1505],cnt[N],val[N],num;
map<int,int> m;
vector<int> pos[N];

IL void pre(int x) {
    int mx=0,ans=0;
    memset(cnt,0,sizeof(cnt));
    for(R i=(x-1)*len+1; i<=n; ++i) {
        cnt[a[i]]++;
        if(cnt[a[i]]>mx||(cnt[a[i]]==mx&&val[a[i]]<val[ans])) mx=cnt[a[i]],ans=a[i];
        f[x][b[i]]=ans;//分块间的最小众数
    }
}

IL int find(int l,int r,int x) {
    return upper_bound(pos[x].begin(),pos[x].end(),r)-lower_bound(pos[x].begin(),pos[x].end(),l);
}

IL void query(int l,int r) {
    int ans=f[b[l]+1][b[r]-1];
    int mx=find(l,r,ans);
    for(R i=l; i<=min(r,b[l]*len); ++i) {
        int tmp=find(l,r,a[i]);
        if(tmp>mx||(tmp==mx&&val[a[i]]<val[ans])) mx=tmp,ans=a[i];
    }
    if(b[l]!=b[r])
        for(R i=(b[r]-1)*len+1; i<=r; ++i) {
            int tmp=find(l,r,a[i]);
            if(tmp>mx||(tmp==mx&&val[a[i]]<val[ans])) mx=tmp,ans=a[i];
        }
    printf("%lld
",val[ans]);
}

signed main() {
    n=read();
    for(R i=1; i<=n; ++i) {
        a[i]=read();
        if(!m[a[i]]) {
            m[a[i]]=++num;
            val[num]=a[i];
        }
        a[i]=m[a[i]];
        pos[a[i]].push_back(i);
    }
    len=80;
    for(R i=1; i<=n; ++i) b[i]=(i-1)/len+1;
    for(R i=1; i<=b[n]; ++i) pre(i);
    for(R i=1; i<=n; ++i) {
        int l=read(),r=read();
        if(l>r) swap(l,r);
        query(l,r);
    }
    return 0;
}
分块9

应用:洛谷P4168 [Violet]蒲公英

#include<bits/stdc++.h>
#define int long long
#define IL inline
#define R register int

using namespace std;
const int N=1e5+5,inf=0x3f3f3f3f;

IL int read() {
    int f=1;
    char ch;
    while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    int res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
    return res*f;
}

int n,a[N],b[N],len,f[1505][1505],cnt[N],val[N],num,lastans;
map<int,int> m;
vector<int> pos[N];

IL void pre(int x) {
    int mx=0,ans=0;
    memset(cnt,0,sizeof(cnt));
    for(R i=(x-1)*len+1; i<=n; ++i) {
        cnt[a[i]]++;
        if(cnt[a[i]]>mx||(cnt[a[i]]==mx&&val[a[i]]<val[ans])) mx=cnt[a[i]],ans=a[i];
        f[x][b[i]]=ans;//分块间的最小众数
    }
}

IL int find(int l,int r,int x) {
    return upper_bound(pos[x].begin(),pos[x].end(),r)-lower_bound(pos[x].begin(),pos[x].end(),l);
}

IL int query(int l,int r) {
    int ans=f[b[l]+1][b[r]-1];
    int mx=find(l,r,ans);
    for(R i=l; i<=min(r,b[l]*len); ++i) {
        int tmp=find(l,r,a[i]);
        if(tmp>mx||(tmp==mx&&val[a[i]]<val[ans])) mx=tmp,ans=a[i];
    }
    if(b[l]!=b[r])
        for(R i=(b[r]-1)*len+1; i<=r; ++i) {
            int tmp=find(l,r,a[i]);
            if(tmp>mx||(tmp==mx&&val[a[i]]<val[ans])) mx=tmp,ans=a[i];
        }
    return val[ans];
}

signed main() {
    n=read();int M=read();
    for(R i=1; i<=n; ++i) {
        a[i]=read();
        if(!m[a[i]]) {
            m[a[i]]=++num;
            val[num]=a[i];
        }
        a[i]=m[a[i]];
        pos[a[i]].push_back(i);
    }
    len=80;
    for(R i=1; i<=n; ++i) b[i]=(i-1)/len+1;
    for(R i=1; i<=b[n]; ++i) pre(i);
    for(R i=1; i<=M; ++i) {
        int l=read(),r=read();
        l=(l+lastans-1)%n+1,r=(r+lastans-1)%n+1;
        if(l>r) swap(l,r);
        lastans=query(l,r);
        printf("%lld
",lastans);
    }
    return 0;
}
P4168代码

洛谷P4135 作诗

和询问区间众数差不多。预处理出分块间正偶数的个数,查询时根据奇偶性具体判断即可。(在洛谷不开O(2)也能过

#include<bits/stdc++.h>
#define int long long
#define IL inline
#define R register int

using namespace std;
const int N=1e5+5,inf=0x3f3f3f3f;

IL int read() {
    int f=1;
    char ch;
    while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    int res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
    return res*f;
}

int n,m,c,a[N],b[N],len,f[1505][1505],cnt[N],val[N],num,lastans,vis[N];

vector<int> pos[N];

IL void pre(int x) {
    int tot=0;
    for(R i=(x-1)*len+1; i<=n; ++i) cnt[a[i]]=0;
    for(R i=(x-1)*len+1; i<=n; ++i) {
        if(cnt[a[i]]!=0&&cnt[a[i]]%2==0) tot--;
        cnt[a[i]]++;
        if(cnt[a[i]]%2==0) tot++;
        f[x][b[i]]=tot;
    }
}

IL int find(int l,int r,int x) {
    return upper_bound(pos[x].begin(),pos[x].end(),r)-lower_bound(pos[x].begin(),pos[x].end(),l);
}

IL int query(int l,int r) {
    int ans;
    if(b[l]==b[r]||b[l]+1==b[r]) {
        ans=0;
        
        for(R i=l; i<=r; ++i) {
            if(vis[a[i]]) continue;
            vis[a[i]]=1;
            int tmp=find(l,r,a[i]);
            if(tmp%2==0) ans++;
        }
        for(R i=l; i<=r; ++i)    vis[a[i]]=0;
    }
    else{
        ans=f[b[l]+1][b[r]-1];//b[l]+1~b[r]-1中的正偶数个数
        int x=b[l]*len+1,y=(b[r]-1)*len;
        
        for(R i=l; i<x; ++i) {
            if(vis[a[i]]) continue;
            vis[a[i]]=1;
            int tmp=find(l,r,a[i]),bef=find(x,y,a[i]);
            if(tmp%2==0) {
                if(bef%2==1||bef==0) ans++;
            } else if(bef&&(bef%2==0)) ans--;
        }
        
        for(R i=y+1; i<=r; ++i) {
            if(vis[a[i]]) continue;
            vis[a[i]]=1;
            int tmp=find(l,r,a[i]),bef=find(x,y,a[i]);
            if(tmp%2==0) {
                if(bef%2==1||bef==0) ans++;
            } else if(bef&&(bef%2==0)) ans--;
        }
        for(R i=l; i<x; ++i) vis[a[i]]=0;
        for(R i=y+1; i<=r; ++i) vis[a[i]]=0;
    }
    return ans;
}

signed main() {
    n=read();
    c=read();
    m=read();
    len=sqrt((double)n/log((double)n)*log(2));
    for(R i=1; i<=n; ++i) {
        a[i]=read();
        pos[a[i]].push_back(i);
        b[i]=(i-1)/len+1;
    }
    for(R i=1; i<=b[n]; ++i) pre(i);
    for(R i=1; i<=m; ++i) {
        int l=read(),r=read();
        l=(l+lastans)%n+1,r=(r+lastans)%n+1;
        if(l>r) swap(l,r);
        lastans=query(l,r);
        printf("%lld
",lastans);
    }
    return 0;
}
P4135代码
 
原文地址:https://www.cnblogs.com/ljy-endl/p/14527589.html