0%

分块

分块的思想就是让每个块内部暴力统计,外部维护块的信息,对于序列长度为 \(n\) 的情况分块的长度就应该设置为 \(len = \sqrt{n}\) ,此时单次区间修改或者查询的时间复杂度为 \(O(\sqrt{n})\) 的。

对于一般的分块,我们可以按下面的代码来实现:

题目链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <bits/stdc++.h>

using namespace std;

#define LL long long

int read(){
int res=0,sign=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')sign=-sign;
for(;ch>='0'&&ch<='9';ch=getchar())res=(res<<3)+(res<<1)+(ch^'0');
return res*sign;
}

const int N=5e4+10;

int n;

int id[N],len;
LL a[N],b[N],s[N];

void add(int l,int r,int c){
int op=id[l],ed=id[r];
if(op==ed){
for(int i=l;i<=r;++i)a[i]+=c,s[op]+=c;
return;
}
for(int i=l;id[i]==op;++i)a[i]+=c,s[op]+=c;
for(int i=op+1;i<ed;++i)b[i]+=c,s[i]+=1ll*c*len;
for(int i=r;id[i]==ed;--i)a[i]+=c,s[ed]+=c;
}

int query(int l,int r,int mod){
int op=id[l],ed=id[r],res=0;
if(op==ed){
for(int i=l;i<=r;++i)res=(1ll*res+a[i]+b[op]+mod)%mod;
return res;
}
for(int i=l;id[i]==op;++i)res=(1ll*res+a[i]+b[op]+mod)%mod;
for(int i=op+1;i<ed;++i)res=(1ll*res+s[i]+mod)%mod;
for(int i=r;id[i]==ed;--i)res=(1ll*res+a[i]+b[ed]+mod)%mod;
return res;
}

int main(){
n=read();len=sqrt(n);
for(int i=1;i<=n;++i){
a[i]=read();
id[i]=(i-1)/len+1;
s[id[i]]+=a[i];
}
for(int i=1,op,l,r,c;i<=n;++i){
op=read(),l=read(),r=read(),c=read();
if(op==0){
add(l,r,c);
}else{
printf("%d\n",query(l,r,c+1));
}
}
return 0;
}