首页 > 其他分享 >分块(板子)

分块(板子)

时间:2024-04-22 21:24:38浏览次数:23  
标签:分块 int 整块 d% 板子 400 区间

“优雅的暴力”——分块

分块是一种暴力的优化,虽然效率比线段树、树状数组等数据结构低的多 \((N+Q)\sqrt{N}\),但是更加灵活。

分块的思想是把整个区间分成几个部分,对于要处理的区间包括两个部分 “整块”,和 区间边缘的“零散块”

“零散块”直接暴力,“整块”进行整体操作即可。

听起来可能和线段树有点像,其实分块可以看成一颗只有三层的树,

区别在于分块可以处理一些区间之间没有结合律的(如众数)。

分块思路相对好想,重点在于如何把整个区间的操作转化为“整块”的操作。

例题


$\mathbb{code}$
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100005;
int n,m;
LL a[N],sum[400],add[400];
int L[400],R[400],bl[N],siz[400];
void bui()
{
	int cnt=sqrt(n);
	for(int i=1;i<=cnt;i++)
	{
		L[i]=n/cnt*(i-1)+1;
		R[i]=n/cnt*i;
	}
	R[cnt]=n;
	
	for(int i=1;i<=cnt;i++)
	{
		for(int j=L[i];j<=R[i];j++)
		{
			bl[j]=i; sum[i]+=a[j];	
		}
		siz[i]=R[i]-L[i]+1;	
	}

}
void mdf(int l,int r,int v)
{
	if(bl[l]==bl[r])
	{
		for(int i=l;i<=r;i++)
		{
			a[i]+=v; sum[bl[l]]+=v;
		}
	}
	else
	{
		for(int i=l;i<=R[bl[l]];i++)
		{
			a[i]+=v; sum[bl[l]]+=v;
		}
		for(int i=L[bl[r]];i<=r;i++)
		{
			a[i]+=v; sum[bl[r]]+=v;
		}
		for(int i=bl[l]+1;i<bl[r];i++)
		{
			add[i]+=v;
		}	
	}
}
LL que(int l,int r)
{
	LL ans=0;
	if(bl[l]==bl[r])
	{
		for(int i=l;i<=r;i++) ans+=a[i]+add[bl[l]];
	}
	else
	{
		for(int i=l;i<=R[bl[l]];i++) ans+=a[i]+add[bl[l]];
		for(int i=L[bl[r]];i<=r;i++) ans+=a[i]+add[bl[r]];
		for(int i=bl[l]+1;i<bl[r];i++) ans+=sum[i]+siz[i]*add[i];
	}
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	bui();
	for(int i=1;i<=m;i++)
	{
		string s; cin>>s;
		if(s[0]=='C')
		{
			int l,r,v;
			scanf("%d%d%d",&l,&r,&v);
			mdf(l,r,v);
		}
		if(s[0]=='Q')
		{
			int l,r;
			scanf("%d%d",&l,&r);
			printf("%lld\n",que(l,r));
		}
	}
	return 0;
}

标签:分块,int,整块,d%,板子,400,区间
From: https://www.cnblogs.com/ppllxx/p/18139292

相关文章

  • 板子速查
    基础二分答案intfind1(intx){intl=1,r=n;while(l<r){intmid=(l+r)>>1;if(check(mid))l=mid+1;elser=mid;}returnl;}//l:第一个不满足check()性质的数。intfind2(intx){intl=1,r......
  • 题解 LGP5397【[Ynoi2018] 天降之物】/ 第四分块
    题解P5397【[Ynoi2018]天降之物】/第四分块题目描述一个长为\(n\)的序列\(a\)。你需要实现\(m\)个操作,操作有两种:把序列中所有值为\(x\)的数的值变成\(y\)。找出一个位置\(i\)满足\(a_i=x\),找出一个位置\(j\)满足\(a_j=y\),使得\(|i-j|\)最小,并输出\(|i-......
  • 蒲公英(分块)
    [Violet]蒲公英题目背景亲爱的哥哥:你在那个城市里面过得好吗?我在家里面最近很开心呢。昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了。我觉得把那么可怕的怪物召唤出来的那个坏蛋也很坏呢。不过奶奶说他是很难受......
  • 分块板子
    预处理voidinit(){clean();scanf("%lld",&n);for(i=1;i<=n;i++)scanf("%lld",&a[i]);sq=sqrt(n);for(i=1;i<=sq;i++){st[i]=n/sq*(i-1)+1;ed[i]=n/sq*i;}ed[sq]=n;for(i=1;i<......
  • 分块--解决区间问题
    什么时候用分块?当你发现正常数据结构无法解决的时候(比如维度特别多,很不方便或者炸空间),或者复杂到要3个$log$以上才能解决时。(主要还是得看数据范围,分块的做法一般都是$O(\sqrt{n})$及以上的如何分块?定一个块长$B$,整个序列就会被分成$\floor{n/B}$块,对于末尾的不......
  • 数论板子
    线性筛求素数intprime[MAXN];//保存素数boolis_not_prime[MAXN]={1,1};//0和1都不是素数//筛选n以内的所有素数voidxxs(intn){for(inti=2;i<=n;++i){if(!is_not_prime[i]){//如果i是素数prime[++prime[0]]=i;......
  • 线段树的板子题
    线段树支持单点修改,单点查询,区间修改,区间查询pushup:子节点更新父节点pushdown:把懒标记向下传build:初始化一颗树modify:修改一个区间query:查询一个区间线段树的完整代码AcWing243.一个简单的整数问题2链接:https://www.acwing.com/problem/content/244/#include<cstdio>......
  • 主席树的板子题
    题解方法1.可持久化线段树(主席树),代码有详细注释做法:先把值离散化在数值上建立线段树,维护每个数值区间中一共有多少个数问题1:如何求整体第K小数?答:二分,如果0~mid中有cnt数,cnt>=k,递归左边,如果cnt<k,递归右边,找k−cnt小的数。时间复杂的logn问题2:求【1,R】这个区间的第K......
  • JAVA 板子
    代码片段1importjava.io.BufferedReader;importjava.io.BufferedWriter;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.OutputStreamWriter;importjava.io.PrintWriter;importjava.io.StreamTokenizer;publicclassMain{stati......
  • Splay 板子
    普通:bool_Start;#include<bits/stdc++.h>usingnamespacestd;#defineilinline#defineTptemplate<typenameT>#defineTstemplate<typenameT,typename..._T>Tpilvoidread(T&x){ x=0;boolf=0;charc=getchar(); for(;!isdigit(c)......