学习笔记:分块

来复习分块啦,真的好简单呀。
分块是优雅的暴力,块长是分块的艺术
思路很简单,大段打标记维护,局部暴力修改就好啦。

复杂度

由块长决定,一般块长取 \(\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;
}
posted @ 2021-12-12 16:41  一程山雪  阅读(35)  评论(0)    收藏  举报