LOJ #6280. 数列分块入门 4-分块(区间加法、区间求和)
题目描述
给出一个长为 nn 的数列,以及 nn 个操作,操作涉及区间加法,区间求和。
输入格式
第一行输入一个数字 nn。
第二行输入 nn 个数字,第 ii 个数字为 a_iai,以空格隔开。
接下来输入 nn 行询问,每行输入四个数字 \mathrm{opt}opt、ll、rr、cc,以空格隔开。
若 \mathrm{opt} = 0opt=0,表示将位于 [l, r][l,r] 的之间的数字都加 cc。
若 \mathrm{opt} = 1opt=1,表示询问位于 [l, r][l,r] 的所有数字的和 \bmod (c+1)mod(c+1)。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入
4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4
样例输出
1
4
数据范围与提示
对于 100\%100% 的数据,1 \leq n \leq 50000, -2^{31} \leq \mathrm{others}1≤n≤50000,−231≤others、\mathrm{ans} \leq 2^{31}-1ans≤231−1。
代码;
1 //#6280. 数列分块入门 4-区间加法,区间求和 2 #include<bits/stdc++.h> 3 using namespace std; 4 typedef long long ll; 5 const int maxn=5e4+10; 6 7 int n,m,pos[maxn]; 8 ll a[maxn],b[maxn],tag[maxn]; 9 10 void update(int l,int r,ll c) 11 { 12 for(int i=l;i<=min(pos[l]*m,r);i++){ 13 a[i]+=c; 14 b[pos[l]]+=c; 15 } 16 if(pos[l]!=pos[r]){ 17 for(int i=(pos[r]-1)*m+1;i<=r;i++){ 18 a[i]+=c; 19 b[pos[r]]+=c; 20 } 21 } 22 for(int i=pos[l]+1;i<pos[r];i++){ 23 tag[i]+=c; 24 } 25 } 26 27 ll query(int l,int r) 28 { 29 ll ans=0; 30 for(int i=l;i<=min(pos[l]*m,r);i++){ 31 ans+=a[i]+tag[pos[l]]; 32 } 33 if(pos[l]!=pos[r]){ 34 for(int i=(pos[r]-1)*m+1;i<=r;i++){ 35 ans+=a[i]+tag[pos[r]]; 36 } 37 } 38 for(int i=pos[l]+1;i<pos[r];i++){ 39 ans+=b[i]+tag[i]*m; 40 } 41 return ans; 42 } 43 44 int main() 45 { 46 scanf("%d",&n); 47 m=sqrt(n); 48 for(int i=1;i<=n;i++){ 49 scanf("%d",&a[i]); 50 b[i]=a[i]; 51 pos[i]=(i-1)/m+1; 52 } 53 for(int i=1;i<=m+1;i++){ 54 int cnt=0; 55 for(int j=(i-1)*m+1;j<=min(i*m,n);j++){ 56 cnt+=a[j]; 57 } 58 b[i]=cnt; 59 } 60 for(int i=1;i<=n;i++){ 61 int op,l,r; 62 ll c; 63 scanf("%d%d%d%lld",&op,&l,&r,&c); 64 if(op==0){ 65 update(l,r,c); 66 } 67 else{ 68 printf("%lld\n",query(l,r)%(c+1)); 69 } 70 } 71 } 72 73 74 /* 75 10 76 1 3 4 2 5 7 11 3 5 1 77 0 1 5 1 78 1 1 7 2 79 0 3 9 1 80 1 4 8 7 81 1 1 10 6 82 1 3 5 3 83 1 5 10 7 84 1 6 10 6 85 1 2 7 4 86 1 2 7 5 87 88 2 89 3 90 5 91 1 92 6 93 3 94 1 95 5 96 */