首页 > 其他分享 >线段树进阶奇淫巧计

线段树进阶奇淫巧计

时间:2024-02-09 21:22:06浏览次数:34  
标签:cnt 进阶 int tr mid 巧计 区间 now 奇淫

看本文文字部分可以少带脑子,但是代码部分仔细看了因为不一定编译了不一定对

动态开点

一般来说线段树的空间开销是比较巨大的,需要 \(4n\) 的空间,一般其实是可以支撑的,但是权值线段树就不一定了。值域级别的代价是支持不了的。

一般在动态开点的前提下只需要支持单点操作

一旦是序列问题还给定初始序列那就别老惦记你那动态开点了,用不了的(除非可持久化)

动态开点是怎么个事?

我们先铺垫一个小函数:newnode

int newnode(){return ++cnt;}

此处以单点赋值单点查询为例

int upd(int p,int l,int r,int x,int val){
	if(!p) p=newnode();
	if(l==r){
		tr[p].v=val;
	}
	else{
		int mid=(l+r)>>1;
		if(x<=mid){
			tr[p].lc=upd(tr[p].lc,l,mid,x,val);
		}
		else{
			tr[p].rc=upd(tr[p].rc,mid+1,r,x,val);
		}
	}
	return p;
}

霍等会,为啥要记录左右儿子?因为现在节点编号不再是父节点乘二而是另算的!

又等下,咋又变成int的函数了?因为你可能需要更改左右儿子的值而不是保持不变

我们类似的又可以写出查询的代码:

int ask(int p,int l,int r,int x){
	if(l==r){
		return tr[p].v;
	}
	int mid=(l+r)>>1;
	if(x<=mid) return ask(tr[p].lc,l,mid,x);
	else return ask(tr[p].rc,mid+1,r,x);
}

和普通的查询没点区别是吧,确实

类似的你也可以单点加区间查询和,但是一旦要打标记,这个动态开点就空间没咋优化还参数大了,一般不会用

大体其实没啥区别,要点就是编号方式不是堆式储存,在访问空节点时新建

标记永久化

有时候我们最喜欢的懒标记可能会太懒了一点,下传不好维护或者下传复杂度、不是 \(O(1)\)

咋办?那就让他懒死直接别动了

直接把pushup和pushdown一起扔掉

例子:线段树1

void build(int now,int l,int r){
	if(l==r){tr[now]=a[l];return;}
	int mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
    tr[now]=tr[ls]+tr[rs];
}

建树没啥区别,看看区间修改

void modify(int now,int l,int r,int L,int R,int k){
	if(L<=l and r<=R){
		tag[now]+=k;
		return ;
	}
	tr[now]+=(R-L+1)*k;
	int mid=(l+r)>>1;
	if(R<=mid){
		modify(ls,l,mid,L,R,k);
	}
	else if(L>mid){
		modify(rs,mid+1,r,L,R,k);
	}
	else{
		modify(ls,l,mid,L,mid,k);
		modify(rs,mid+1,r,mid+1,R,k);
	}
}

什么原理?

我们可以考虑对于某个区间的修改对结果的影响。因为我们没有要pushup,我们再向下递归的时候考虑每个区间需要被改动多少

如果目标区间完全被包含在当前区间内,加上目标区间长度*加几

向下递归时,如果目标区间完全在某个子树内,无疑直接递归下去

如果 \(mid\) 分开了目标区间,显然位于另一个子树的部分区间对于这个子树是没有贡献的

然后继续递归

int query(int now,int l,int r,int L,int R){
	int cnt=(R-L+1)*tag[now];
	if(L<=l and r<=R) return tr[now]+cnt;
	int mid=(l+r)>>1;
	if(R<=mid) cnt+=query(ls,l,mid,L,R);
	else if(L>mid) cnt+=query(rs,mid+1,r,L,R);
	else{
		cnt+=query(ls,l,mid,L,mid);
		cnt+=query(rs,mid+1,r,mid+1,R);
	}
	return cnt;
}

关于贡献的考虑略去,我们计算完正常的答案后要注意,当前答案要加上目标区间*当前tag,这是这一个节点的tag对答案的贡献

同时这里可以解释为什么上面要先判断当前区间和目标区间包含关系,因为tag对于答案的贡献要防止重复计算

然后就没了,这就是标记永久化

to be upd:可持久化,矩阵和标记,主席树

标签:cnt,进阶,int,tr,mid,巧计,区间,now,奇淫
From: https://www.cnblogs.com/exut/p/18012428

相关文章

  • 最新Burp Suite进阶技术
    Burp Suite进阶1.Burp ScannerBurpScanner主要用于自动检测Web系统的各种漏洞。本节介绍BurpScanner的基本使用方法,在实际使用中可能会有所改变,但大体环节如下。首先,确认BurpSuite正常启动并完成浏览器代理的配置。然后进入BurpProxy,关闭代理拦截功能,快速浏览需要扫描的域......
  • Vim进阶学习
    vim的进阶学习分为两部分:自定义配置文件以及插件的使用。自定义配置文件在这里我们需要修改.vimrc文件,稍后我会将我的配置文件发在文章结尾,所有的配置都是参考b站的课程:传送门。首先就是"代码高亮syntaxon"设置行号setnumber"主题使用OneDarkcolorschemeonedark"......
  • MySQL-进阶
    一、MySQL体系结构1.连接层:一些客户端和连接服务,完成连接处理、授权认证及相关操作2.服务层:完成大多数核心服务的功能,比如SQL的分析和优化3.引擎层:负责MySQL中数据的存储和提取4.存储层:数据存储层,将数据存储在文件系统上,并完成与存储引擎的交互二、存储引擎(MySQL的核心)1.定......
  • 华为云软件开发生产线CodeArts开发者实践8件套——开发者的进阶宝典!
    华为云软件开发生产线CodeArts是一站式DevSecOps平台,集华为多年研发实践,前沿研发理念,领先研发工程能力于一体,覆盖软件开发全生命周期,开箱即用,为您提供软件开发的一切。为帮助开发者快速上手CodeArts,我们汇聚了精品视频课程、在线动手实验、职业认证及丰富示例代码,助您扫平产品使用......
  • 耗时一个月我问遍了身边的大佬,零基础自学Java的路线,适用程序员入门&进阶,Java学习路线,2
    作为一个有志于成为Java程序员的你,或许正处在技术生涯的起点,或许已经走过了入门的道路,期待跨越进阶的门槛?无论处于哪个阶段,一条明确的学习路线都至关重要,通过向众多行业大佬请教、反复探索和实践,总结出一套适用于零基础自学者大学四年Java学习路线,也同样适用于从初级到研发专家的学......
  • RK3568驱动指南|驱动基础进阶篇-进阶7 向系统中添加一个系统调用
      瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和MaliG522EE图形处理器。RK3568支持4K解码和1080P编码,支持SATA/PCIE/USB3.0外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568支持安卓11和linux系统,主......
  • 关于Windows11的优化内容 - 进阶者系列 - 学习者系列文章
          这几天无事,想起上次刚重装的Windows11操作系统,对于系统优化的内容想记录一下,以前没写过相关的博文,这次就做个记录吧。对于Windows11,已经出来几年了,相关的设置啥的也有,就是优化方面的软件和设置也有相关的,这次就把笔者这边所有相关的优化工具软件和脚本啥的一并发布......
  • 【APP自动化进阶】pytest+appium多设备并发
    并发编程基础【Python进阶】并发编程方式APP自动化并发项目实战项目步骤获取设备信息并根据设备数量开启n个进程appium服务处理pytest前置处理开启appium服务pytest后置处理关闭appium服务pytest进行用例执行,并输出报告数据等待进程执行完毕生成每个设备的allure报告......
  • 【Python进阶】并发编程方式
    并发编程方式有哪些?threading模块---线程asyncio模块---协程concurrent.futures模块---进程+线程(应用于异步调用)multiprocessing模块---进程进程、线程、协程?进程:运行起来的程序就是进程,是操作系统分配资源的最小单位。线程:线程是进程的组成部分,一个进程可以拥有多个线......
  • 【pytest进阶】pytest之hook函数
    什么是hook函数比如说你写了一个框架类的程序,你希望这个框架可以“被其他的代码注入”,即别人可以加入代码对你这个框架进行定制化,该如何做比较好?一种很常见的方式就是约定一个规则,框架初始化时会收集满足这个规则的所有代码(文件),然后把这些代码加入到框架中来,在执行时一并执行......