学习笔记:分块
来复习分块啦,真的好简单呀。
分块是优雅的暴力,块长是分块的艺术
思路很简单,大段打标记维护,局部暴力修改就好啦。
复杂度
由块长决定,一般块长取 \(\sqrt n\),时间复杂度为 \(O(n\sqrt n)\),可过 \(10^5\)。
复杂度与块长关系推导
待补
应用
区间修改单点查询
传送门:数列分块 1
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 50000 + 10;
int n;
int a[N],spl[N],L[N],R[N],tag[N];
void change(int l,int r,int v)
{
int p = spl[l],q = spl[r];
if(p == q)
{
for(int i = l;i <= r;i++) a[i] += v;
return ;
}
if(p == q - 1)
{
tag[p] += v;
tag[q] += v;
for(int i = L[p];i < l;i++) a[i] -= v;
for(int i = r + 1;i <= R[q];i++) a[i] -= v;
return ;
}
for(int i = p + 1;i <= q - 1;i++) tag[i] += v;
for(int i = l;i <= R[p];i++) a[i] += v;
for(int i = L[q];i <= r;i++) a[i] += v;
}
signed main()
{
scanf("%lld",&n);
for(int i = 1;i <= n;i++)
scanf("%lld",&a[i]);
int block = sqrt(n);
for(int i = 1;i <= block;i++)
{
L[i] = (i - 1) * block + 1;
R[i] = i * block;
}
if(R[block] < n) block++,L[block] = R[block - 1] + 1,R[block] = n;
for(int i = 1;i <= block;i++)
for(int j = L[i];j <= R[i];j++)
spl[j] = i;
for(int i = 1;i <= n;i++)
{
int opt,l,r,v;
scanf("%lld%lld%lld%lld",&opt,&l,&r,&v);
if(l > r) swap(l,r);
if(opt == 0) change(l,r,v);
else printf("%lld\n",a[r] + tag[spl[r]]);
}
return 0;
}
区间修改区间求和
传送门:数列分块 4
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 50000 + 10;
int n,block;
int a[N],L[N],R[N],spl[N],sum[N],tag[N];
void change(int l,int r,int v)
{
int p = spl[l],q = spl[r];
if(p == q)
{
for(int i = l;i <= r;i++) a[i] += v;
sum[p] += v * (r - l + 1);
return ;
}
for(int i = p + 1;i <= q - 1;i++) tag[i] += v;
for(int i = l;i <= R[p];i++) a[i] += v;
sum[p] += v * (R[p] - l + 1);
for(int i = L[q];i <= r;i++) a[i] += v;
sum[q] += v * (r - L[q] + 1);
}
int query(int l,int r,int mod)
{
int p = spl[l],q = spl[r],res = 0;
if(p == q)
{
for(int i = l;i <= r;i++) res = (res + a[i]) % mod;
res = (res + tag[p] * (r - l + 1) % mod) % mod;
return res;
}
for(int i = p + 1;i <= q - 1;i++) res = ((res + sum[i]) % mod + tag[i] * (R[i] - L[i] + 1) % mod) % mod;
for(int i = l;i <= R[p];i++) res = (res + a[i]) % mod;
res = (res + tag[p] * (R[p] - l + 1) % mod) % mod;
for(int i = L[q];i <= r;i++) res = (res + a[i]) % mod;
res = (res + tag[q] * (r - L[q] + 1) % mod) % mod;
return res;
}
signed main()
{
scanf("%lld",&n);
for(int i = 1;i <= n;i++) scanf("%lld",&a[i]);
block = sqrt(n);
for(int i = 1;i <= block;i++)
{
L[i] = (i - 1) * block + 1;
R[i] = i * block;
}
if(R[block] < n) block++,L[block] = R[block - 1] + 1,R[block] = n;
for(int i = 1;i <= block;i++)
for(int j = L[i];j <= R[i];j++)
spl[j] = i,sum[i] += a[j];
for(int i = 1;i <= n;i++)
{
int opt,l,r,v;
scanf("%lld%lld%lld%lld",&opt,&l,&r,&v);
if(opt == 0) change(l,r,v);
else printf("%lld\n",query(l,r,v + 1) % (v + 1));
}
return 0;
}

浙公网安备 33010602011771号