题解 P5309 【[Ynoi2011] 初始化】
FutaRimeWoawaSete · · 题解
本来应该是一道不难的分块……结果还是做的很烂。
知识点:阈值分治 + 分块 。
首先我们先考虑一下正常点的数据结构,发现像线段树和树状数组好像生搬硬套都有点难搞,所以考虑暴力数据结构分块。
接着考虑一下直接暴力维护,我们只要判断一下当前的修改次数有没有超过
分析到这里,我们已经可以想到
我们再仔细观察操作,发现这个操作是针对全局而言的,那么我们可不可以从宏观大局上来维护呢?
接着又发现如果我们模拟分块,把原序列分成长为
我们考虑分块查询时是怎么查询的,中间一串连着的块两边一些边角块,由于无法维护所有的
考虑均摊时间复杂度。现在我们用一个前缀和以及后缀和来维护每种
for(register int i = y ; i <= x ; i ++) pre[x][i] = pre[x][i] + z;
for(register int i = y ; i >= 1 ; i --) suf[x][i] = suf[x][i] + z;
很显然这样的暴力时间复杂度在限制了
在计算时,我们只要像分块一样计算出左端点在当前
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int Len = 2e5 + 5 , SIZE = 505 , mod = 1e9 + 7;
inline int read() {
char ch = getchar();
int x = 0;
while (ch < '0' || ch > '9') ch = getchar();
while ('0' <= ch && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x;
}
inline void write(long long x) {
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
int n,m,pos[Len],L[SIZE],R[SIZE],t;
long long sum[SIZE],pre[SIZE][SIZE],suf[SIZE][SIZE],a[Len];
inline void Upd(int x,int y,int z)
{
if(x >= t)
{
for(register int i = y ; i <= n ; i += x)
{
a[i] = a[i] + z;
sum[pos[i]] = sum[pos[i]] + z;
}
}
else
{
for(register int i = y ; i <= x ; i ++) pre[x][i] = pre[x][i] + z;
for(register int i = y ; i >= 1 ; i --) suf[x][i] = suf[x][i] + z;
}
}
inline long long qbsum(int l,int r)
{
int Lid = pos[l] , Rid = pos[r] ; long long res = 0;
if(Lid == Rid) for(register int i = l ; i <= r ; i ++) res = res + a[i];
else
{
for(register int i = l ; i <= R[Lid] ; i ++) res = res + a[i];
for(register int i = Lid + 1 ; i <= Rid - 1 ; i ++) res = res + sum[i];
for(register int i = L[Rid] ; i <= r ; i ++) res = res + a[i];
}
return res;
}
inline long long all_sum(int l,int r)
{
long long Blocksum = qbsum(l , r);
for(register int i = 1 ; i < t ; i ++)
{
int Lb = (l - 1) / i + 1 , Rb = (r - 1) / i + 1;
if(Lb == Rb)
{
Blocksum -= pre[i][(l - 1) % i];
Blocksum += pre[i][(r - 1) % i + 1];
}
else Blocksum = Blocksum + (Rb - Lb - 1) * pre[i][i] + suf[i][(l - 1) % i + 1] + pre[i][(r - 1) % i + 1];
}
return Blocksum % mod;
}
signed main()
{
n = read() , m = read();
t = sqrt(n);
for(register int i = 1 ; i <= n ; i ++) a[i] = read();
for(register int i = 1 ; i <= t ; i ++) L[i] = (i - 1) * t + 1 , R[i] = i * t;
R[t] = n;
for(register int i = 1 ; i <= t ; i ++)
for(register int j = L[i] ; j <= R[i] ; j ++) pos[j] = i;
for(register int i = 1 ; i <= n ; i ++) sum[pos[i]] = sum[pos[i]] + a[i];
for(register int i = 1 ; i <= m ; i ++)
{
int opt,x,y,z;opt = read();
if(opt == 1){x = read() , y = read() , z = read() , Upd(x , y , z);}
else{x = read() , y = read() ; write(all_sum(x , y)) , putchar('\n');}
}
return 0;
}