1. 程式人生 > 其它 >學習筆記:分塊

學習筆記:分塊

來複習分塊啦,真的好簡單呀。
分塊是優雅的暴力,塊長是分塊的藝術
思路很簡單,大段打標記維護,區域性暴力修改就好啦。

複雜度

由塊長決定,一般塊長取 \(\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;
}