首页 > 其他分享 >分块入门

分块入门

时间:2024-07-17 21:41:07浏览次数:9  
标签:长为 分块 int tag 区间 操作 id 入门

基本思想

把一个需要操作的序列分成若干块,分别处理,从而优化时间复杂度。

容易证明块长为 \(\sqrt n\) 时复杂度最优。

分块常规单次操作复杂度为 \(\mathcal{O}(\sqrt n)\),一般可以当做 \(\mathcal{O}(\log^2n)\) 来计算复杂度。

接下来给几道例题。

T1

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,单点查值。

就当模板放了。

void add(int l,int r,int c)
{
	int sid=id[l],eid=id[r];
	if(sid==eid)
	{
		for(int i=l;i<=r;i++)
		a[i]+=c;
		return ;
	}
	for(int i=l;id[i]==sid;i++)a[i]+=c;
	for(int i=sid+1;i<eid;i++)tag[i]+=c;
	for(int i=r;id[i]==eid;i--)a[i]+=c;
}

T2

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的元素个数。

对于区间加法,类似线段树设置懒标记,对于查询操作,可以用二分解决。我们每次区间加法之后对所有涉及到的不完整区间重新排序,保证可以二分找到给定值,对于完整区间,由于顺序不变,则更新 \(tag\) 值即可。

具体的,我们对于每一个块,用一个 \(vector\) 记录值,每次排序对 \(vector\) 排序,可以证明复杂度正确。

放一下查询和更新的代码:

void work(int x)
{
	v[id[x]].clear();
	for(int i=(id[x]-1)*len+1;i<=min(n,id[x]*len);i++)
	v[id[x]].push_back(a[i]);
	sort(v[id[x]].begin(),v[id[x]].end());
}
int ask(int l,int r,int c)
{
	int sid=id[l],eid=id[r],ans=0;
	if(sid==eid)
	{
		for(int i=l;i<=r;i++)if(a[i]+tag[id[l]]<c)ans++;
		return ans;
	}
	for(int i=l;id[i]==sid;i++)if(a[i]+tag[id[l]]<c)ans++;
	for(int i=sid+1;i<eid;i++)ans+=lower_bound(v[i].begin(),v[i].end(),c-tag[i])-v[i].begin();
	for(int i=r;id[i]==eid;i--)if(a[i]+tag[id[r]]<c)ans++;
	return ans;
}

T3

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的前驱(比其小的最大元素)。

和上一道题很类似,只是对于查询操作,我们二分找到每个块里面符合条件的最大值,取总最大值即可。

查询部分:

int sid=id[l],eid=id[r],ans=-1;
if(sid==eid)
{
	for(int i=l;i<=r;i++)if(a[i]+tag[id[l]]<c)ans=max(ans,a[i]+tag[id[l]]);
	return ans;
}
for(int i=l;id[i]==sid;i++)if(a[i]+tag[id[l]]<c)ans=max(ans,a[i]+tag[id[l]]);
for(int i=sid+1;i<eid;i++)
{
	int x=c-tag[i];
	int y=lower_bound(v[i].begin(),v[i].end(),x)-v[i].begin();
	if(--y>=0)
		ans=max(ans,v[i][y]+tag[i]);
}
for(int i=r;id[i]==eid;i--)if(a[i]+tag[id[r]]<c)ans=max(ans,a[i]+tag[id[r]]);
return ans;

T4

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,区间求和。

简单,模拟线段树的思路,记录区间懒标记 \(tag\),修改的时候对于完整区间只更新 \(tag\) 值,查询的时候对于不完整的块,让每个元素加上他所在区间的 \(tag\) 值累加,对于完整的块,则让区间和加上 \(tag\times len\)(\(len\) 为块长)后累加答案即可。

太简单,代码不放了。

T5

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间开方,区间求和。

势能分析,由于 \(\sqrt 1=1\),所以我们用一个布尔数组 \(f\) 表示当前块是否已经全部小于等于 \(1\),每次修改的时候对于 \(f_i\le 1\) 的块跳过,否则暴力修改即可。

整块修改部分代码:

for(int i=sid+1;i<eid;i++)
	if(!f[i]) 
	{
		f[i]=1;
		for(int j=(i-1)*len+1;j<=min(n,i*len);j++) 
		{
			tag[i]=tag[i]-a[j]+sqrt(a[j]);
			a[j]=sqrt(a[j]);
			if(a[j]!=0&&a[j]!=1)
				f[i]=0;
		}
	}

T6

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及单点插入,单点询问。

其实稍微想一想就发现,我们只需要维护每一个块的内部排列即可,对于每个修改操作,在块内正常暴力修改,对于每个查询操作,从 \(1\) 开始跑,每次减去当前块长,最后直接输出即可。

放一下代码:

void add(int x,int k)
{
	int sum=0;
	for(int i=1;i;i++)
	{
		if(x<v[i].size())
		{
			v[i].push_back(maxn);
			for(int j=v[i].size()-1;j>x;j--)
			{
				v[i][j]=v[i][j-1];	
			}
			v[i][x]=k;
			return ;
		}
		x-=v[i].size();
	}
}
void ask(int x)
{
	int sum=0;
	for(int i=1;;i++) 
	{
		if(x<v[i].size()) {cout<<v[i][x]<<'\n';return ;}
		x-=v[i].size();
	}
}

T7

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间乘法,区间加法,单点询问。

左转线段树,模拟懒标记就行了。有点难写,所以代码不放了。

T8

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间询问等于一个数 \(c\) 的元素,并将这个区间的所有元素改为 \(c\)。

标签:长为,分块,int,tag,区间,操作,id,入门
From: https://www.cnblogs.com/Lydic/p/18308349

相关文章

  • 什么是大模型?(超详细)大模型从入门到精通,看这一篇就够了
    大模型的定义大模型是指具有数千万甚至数亿参数的深度学习模型。近年来,随着计算机技术和大数据的快速发展,深度学习在各个领域取得了显著的成果,如自然语言处理,图片生成,工业数字化等。为了提高模型的性能,研究者们不断尝试增加模型的参数数量,从而诞生了大模型这一概念。大模......
  • CAN协议介绍与入门
    CAN(ControllerAreaNetwork)协议是一种用于实时应用的串行通信协议,最初由德国Bosch公司开发,主要用于汽车行业的电子系统之间进行数据交换,但其应用已经扩展到了其他领域,如工业自动化、医疗设备和航空航天。下面是一个基本的CAN协议入门教程概览:1.CAN协议概述背景与历......
  • gitee入门_如何上传文件
    前提条件:1,已经安装完git相关环境2,在gitee上已经创建完仓库1,初始化本地仓库在本地新建一个文件夹,点击鼠标右键,选择gitbash在打开后输入代码:gitinit2,同步文件打开gitee,选择自己的仓库,复制输入:gitremoteaddorigin此处粘贴然后再执行上述图片中的第二步第三步......
  • kettle从入门到精通 第七十七课 ETL之kettle kettle执行存储过程,接收数据集
    场景:kettle调用存储过程,存储过程中通过select*fromtable方式返回结果集,kettle接收结果集。 解决方案:1)借助临时表。2)表输入步骤。今天主要讲解表输入。1、创建一个无参存储过程,脚本中通过select*fromt1返回数据集。脚本如下:usetest;dropprocedureifexistssp_wi......
  • NFS服务器配置全攻略:从入门到精通
    NFS服务的配置NFS服务器配置文件NFS服务器共享目录配置文件为/etc/exports,此文件的语法结构如下:共享目录的绝对路径客户端地址1(选项)客户端地址2(选项)...NFS服务器在共享一个目录的时候,客户端选项部分定义允许哪些主机可以访问此共享目录,客户端地址与选项之间没......
  • TS 入门(七):TypeScript模块与命名空间
    目录前言回顾泛型编程1.模块a.导入和导出b.默认导出c.重命名导入和导出2.命名空间a.定义命名空间b.嵌套命名空间3.动态导入与条件导入a.动态导入b.条件导入结语前言在前几章中,我们学习了TypeScript的基础知识、函数与对象类型、接口与类、以及泛型编......
  • Task2:从baseline代码详解入门深度学习
    Task2:从baseline代码详解入门深度学习准备工作数据集数据集被划分为三种,分别是:训练集,开发集测试集。训练集数量最多,用于训练模型,开发集用于在训练中不断调整模型的参数,架构,测试集用于测试模型模型基于seq2seq模型主要由encoderdecoder两部分构成使用GRU模型大致可以理......
  • 第二课堂笔记:python入门
    数据类型和操作python的常见数据类型标准数据类型不可变数据Number(数字)String(字符串)Tuple(元组)可变数据List(列表)Set(集合)Dictionary(字典)其他Type(类型)Numberint(整数)离散的数据类型float(浮点数)浮点数误差:​ 精确计算浮点数importdecimala=decimal.......
  • 基础知识(JAVA入门)
    常用的CMD命令盘符名称+冒号说明:盘符切换dir说明:查看当前路径下的内容cd说明:进入单级目录cd..说明:回退到上一级目录cd目录1\目录2....说明:进入多级目录cls说明:清屏exit说明:退出命令提示符窗口环境变量我们想要在任意的目录下都可以打开指定的软件。就可以把软件的路......
  • 15分钟快速了解图新地球能做什么,解决什么问题,快速入门
    1.图新地球桌面端是什么1.1官方定义图新地球桌面端(LSV)是一款集多源数据加载、应用分析、演示汇报为一体的三维GIS软件。采用了中科图新自主研发的国产三维地图引擎,支持各类无人机航测、CAD、BIM、规划成果等多源数据的加载融合;实现了BIM+GIS技术在实际业务中的应用落地......