首页 > 其他分享 >线段树进阶

线段树进阶

时间:2024-02-16 15:55:07浏览次数:31  
标签:return 进阶 rs int 线段 mid 复杂度

线段树进阶

动态开点

定义

动态存储数据的线段树,可以优化空间复杂度

实现

为了避免 \(N<<1\) ,不再使用完全二叉树存储,而记录左右儿子 \(ls,rs\) 此外需要 \(tot\) 记录已经开了多少点

在递归时要记录点的左右区间,确保开点时能知道区间大小

void modify(int &p,int L,int R,int l,int r,int v){//big->pointlr small->modifylr
	if(!p)p = mknode();
	t[p].l = L,t[p].r = R;
	int siz=R-L+1;
	if(l<=L&&R<=r){
		t[p].sum += 1ll*siz(p)*v;
		t[p].add += v;
		return;
	}
	pushdown(p);
	int mid=L+R>>1;
	if(l<=mid)
		modify(t[p].ls,L,mid,l,r,v);
	if(r>mid)
		modify(t[p].rs,mid+1,R,l,r,v);
	pushup(p);
}
long long query(int p,int L,int R,int l,int r){
	if(!p)return 0;//没有该节点 返回0
	if(l<=L&&R<=r)return t[p].sum;
	int mid=L+R>>1;
	long long ans=0;
	pushdown(p);
	if(l<=mid)ans+=query(t[p].ls,L,mid,l,r);
	if(r>mid)ans+=query(t[p].rs,mid+1,R,l,r);
	return ans;
}

空间复杂度

\(O(min(m\log n,n*2))\)

不要像我一样 mknode 写错 tot 加了两次,搞得数据隔一点存一个然后 RE

还要注意 root 也会占线段树的空间为 O(n(\logn + 1))

线段树合并

需要用到动态开点。

不过就是遍历树然后刷新节点,然后pushup。时间复杂度要具体情况具体分析,比如雨天的尾巴,据分析。线段树合并过程中发生递归,p,q之一会被删除,所以merge函数被调用的次数不超过所有点数加一。 \(O((m+n)\log |V|)\)

int merge(int p,int q,int L,int R){
	if(!p)return q;
	if(!q)return p;
	if(L==R){
		t[p].dat += t[q].dat;
		t[p].pos = t[p].dat?L:0; 
		return p;
	}
	int mid=L+R>>1;
	t[p].ls = merge(t[p].ls,t[q].ls,L,mid);
	t[p].rs = merge(t[p].rs,t[q].rs,mid+1,R);
	pushup(p);
	return p;
}

优化建图

一个区间每个点对一个点进行连边。可以建立线段树,线段树内部边权根据问题而定。如果要分入边和出边,就建两棵树,入树和出树,注意两棵树的叶子节点是一样的,可以使用动态开点实现。

标记永久化

适当的时候,不下传标记,而是查询时一层层递归,累加答案,优化时间复杂度。

可持久化

参见主席树

练习题

学而不思则妄,思而不学则殆

【模板】线段树 1 提示:动态开点

【模板】线段树合并 提示:线段树合并,树上差分

【模板】线段树分裂

Legacy 提示:线段树优化建图

参考资料

线段树合并时间复杂度证明

标签:return,进阶,rs,int,线段,mid,复杂度
From: https://www.cnblogs.com/life-of-a-libertine/p/18017226

相关文章

  • 线段树进阶
    线段树进阶线段树分治P5787判断二分图可以用扩展域并查集,采用线段树分治,线段树上的每一个结点作为每一段时间。每个结点上的修改和回溯需要用到可撤销的并查集。时间复杂度\(O(n\logk\logn)\)扫描线扫描线求矩形面积#include<bits/stdc++.h>usingnamespacestd;typ......
  • 大数进阶(1)——反射(Π1)
    一点吐槽序数分析(OrdinalAnalysis)这一脉实际上是从证明论衍生出来的,因此去找文献通常会找到各种证明某一公理系统强度的文献,并没有系统的综述踏入序数之后,几乎没有统一记号,需要在各人的记号中切换,加之数理逻辑本身就需要一堆新记号,可谓是乱七八糟,有一种踏入前沿的美(确实即使从G......
  • 线段树
    【前置知识】运算律,单位元。运算律基本就是交换律、结合律、分配律。单位元:假设我们现在有一个运算\(\bigoplus\)。如果\(a\bigoplusb=b\bigoplusa=a\),称\(b\)是运算\(\bigoplus\)的单位元。【线段树】线段树是一个树形数据结构。满二叉树;倍增的思想,分治的手......
  • 李超线段树
    李超线段树线段树的扩展版本用来动态维护平面上直线支持插入直线/线段,查询横坐标某处覆盖的线中纵坐标最大/最小值可以用于斜率优化DP插入直线这里直线是线段树上维护的信息,表示当前区间中点处最优的直线同时相当于区间修改,直线也是标记,这个区间内都可能有这条直线但是标......
  • 2024.2.14 WC24 线段树 / CF1572D / lgP3679
    西安Day1。感冒还没好,牙龈炎也没好,明天还要考试,又要坐牢了/kk。今天是tyy的图论选讲,感觉前面网络流部分还是在线的,平面图部分毒瘤tyy拿出了他的员交课件,恐怖,直接下线了。看了NAVI和Faze的预选赛,你们俩怎么都打的这么稀碎/fn。Override真好听。「WC2024」线段树我......
  • 字符串进阶题目选做
    字符串进阶一些不那么裸的字符串题,甚至出现了parent树优化建图这种离谱的东西。前置知识:kmp,字符串哈希,AC自动机,SA,SAM,ManacherCF914FSubstringsinaString题意:给定字符串,要求支持单点修改,询问时给出字符串,求在\([l,r]\)中出现多少次。思路:考虑一般的字符串维护方法都......
  • 线段树分治学习笔记
    线段树分治线段树分治是一种可以离线处理带撤销问题的常用手段。一般而言,题目中加入操作很好维护,但删除操作不好维护,这时可以对时间维建线段树,把每一个操作加入其存在时间段对应的线段树节点上,然后处理所有询问,进入一个节点时将这个节点里的操作加入,递归左右儿子,然后撤销这一次做......
  • 线段树进阶奇淫巧计
    看本文文字部分可以少带脑子,但是代码部分仔细看了因为不一定编译了不一定对动态开点一般来说线段树的空间开销是比较巨大的,需要\(4n\)的空间,一般其实是可以支撑的,但是权值线段树就不一定了。值域级别的代价是支持不了的。一般在动态开点的前提下只需要支持单点操作一旦是序......
  • 线段树
    3.区间操作与Lazy-Tag本节介绍线段树的核心操作Lazy-Tag,并给出区间修改\(+\)区间查询的模板。在线段树上,如果直接进行区间修改,时间复杂度为\(\mathcal{O}(N\logN)\)。而Lazy-Tag可以将其降为\(\mathcal{O}(\logN)\)。Lazy-Tag方法用\(lz_p\)统一记录区间\(p......
  • 线段树维护字符串哈希
    [ABC331F]PalindromeQuery#include<bits/stdc++.h>usingnamespacestd;#defineendl"\n"#defineintlonglongtypedeflonglongll;constintbase=131;constintp1=1222827239;constintN=1e6+100;intn,q,pn[N];strings......