luogu P5309 [Ynoi2011] 初始化
https://www.luogu.com.cn/problem/P5309
分块+根号分治
考虑周期长度x
- 如果 x > = n x >= \sqrt{n} x>=n 就暴力改
- 否则每一个周期单独考虑,然后把结果加起来
对于一个周期 x x x,它对询问 [ l , r ] [l,r] [l,r]对贡献一定是完整的几块再加上左右两边的散块,左右两边的散块可以用x对于每个y的前缀和和后缀和来快速计算,如果没有完整的一块就用前缀和减一下
总的来说就是分两部分计算,算本来的和还有每个周期的贡献和
code:
#include<bits/stdc++.h>
#define N 200050
#define mod 1000000007
using namespace std;
void add(int &x, int y) { x += y;
if(x >= mod) x -= mod;
}
void sub(int &x, int y) { x -= y;
if(x < 0) x += mod;
}
int a[N], bel[N], sum[N], pre[505][505], suf[505][505], n, m, blo;
void update(int x, int y, int z) {
if(x >= blo) {
for(int i = y; i <= n; i += x) {
add(a[i], z), add(sum[bel[i]], z);
}
return ;
}
for(int i = y; i <= x; i ++) add(pre[x][i], z);
for(int i = 1; i <= y; i ++) add(suf[x][i], z);
}
int getsum(int l, int r) {
int ans = 0;
if(bel[l] == bel[r]) {
for(int i = l; i <= r; i ++) add(ans, a[i]);
return ans;
}
for(int i = bel[l] + 1; i <= bel[r] - 1; i ++) add(ans, sum[i]);
for(int i = l; i <= bel[l] * blo; i ++) add(ans, a[i]);
for(int i = (bel[r] - 1) * blo + 1; i <= r; i ++) add(ans, a[i]);
return ans % mod;
}
int query(int l, int r) {
int ans = getsum(l, r);
for(int x = 1; x < blo; x ++) {
int L = (l - 1) / x + 1, R = (r - 1) / x + 1;
if(L == R) sub(ans, pre[x][(l - 1) % x]), add(ans, pre[x][(r - 1) % x + 1]);
else ans = (ans + 1ll * (R - L - 1) * pre[x][x] + pre[x][(r - 1) % x + 1] + suf[x][(l - 1) % x + 1]) % mod;
}
return ans;
}
int main() {
scanf("%d%d", &n, &m); blo = sqrt(n) + 1;
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), bel[i] = (i - 1) / blo + 1, a[i] %= mod, add(sum[bel[i]], a[i]);
while(m --) {
int o, x, y, z;
scanf("%d", &o);
if(o == 1) {
scanf("%d%d%d", &x, &y, &z);
update(x, y, z % mod);
} else {
scanf("%d%d", &x, &y);
printf("%d\n", query(x, y));
}
}
return 0;
}