首页 > 其他分享 >线段树

线段树

时间:2024-08-19 11:28:22浏览次数:12  
标签:limits 线段 节点 sum 区间 ll

完成时间: \(2024.5.31\sim202?.?.?\)

工程表

\(日期\) \(完工\)
\(2024.6.1\) \(2.3,3.1,3.2,3.3\)
\(2024.6.5\) \(2.1,2.2\)
\(2024.6.8\) \(3.4\)

线段树入门

P2068 统计和

P1531 I Hate It

打算写,鸽一鸽。

线段树基础

懒标记线段树

P3372 【模板】线段树 1

如果暴力修改的话,时间复杂度会退化到 \(O(n^2)\)。

受到第一道例题启发,我们将修改的区间划分成 \(\log n\) 个区间。不同的是,我们没必要将这个区间里的每一个数都修改。

例如我们修改了 \([3,4]\),后一次查询操作查询了 \([2,5]\)。不过我们遍历到区间 \([3,4]\) 时直接返回了这个区间的 \(sum\),而并没有用到 \([3,3],[4,4]\) 的相关信息。我们只需要直接修改 \([3,4]\) 的 \(sum\) 值(同理,如果我们要修改一个区间 \([l,r]\) 的信息,以这道题为例,区间加 \(k\),区间和就加上了 \((r-l+1)\times k\) )。就可以保证这几次询问的正确性。

但如果下一次询问要询问 \([1,3]\),需要用到 \([3,3]\) 的信息。但我们只修改了 \([3,4]\) ,却没有修改 \([3,3]\)。这岂不穿帮了?所以我们需要在每个节点处维护一个变量,表示
当前区间已经修改,但其子节点还为修改」的信息。当需要访问一个节点的子节点时,就下传这个变量并清零。

我们令其为 \(tag\)(下文称之为“懒标记”)。我们只要在将要遍历一个区间的子节点时,将这个区间的 \(tag\) 下传给子节点,然后清空。就可以始终保持当前区间处于「所有相关操作均已进行」的状态。

注意的是,修改子节点后,一定要 \(\text{push_up}\)。

时间复杂度:在线段树中的查询或修改中,深度为 \(i\) 的节点向深度为 \(i+1\) 的节点下传懒标记的次数不会超过 \(2\),深度为 \(i\) 的节点通过深度为 \(i+1\) 的节点进行 \(\text{push_up}\) 的次数也不会超过 \(2\) 次。时间复杂度为 \(O(n\log n)\)。

搞清楚这些,就很好做了:

点击查看代码
ll update(int p){
	return a[2*p].sum+a[2*p+1].sum;
}
void push_down(int p){
	int lt=2*p,rt=2*p+1;
	a[lt].lazy+=a[p].lazy;a[lt].sum+=(a[lt].right-a[lt].left+1)*a[p].lazy;
	a[rt].lazy+=a[p].lazy;a[rt].sum+=(a[rt].right-a[rt].left+1)*a[p].lazy;
	a[p].lazy=0;
}	
void add(int l,int r,int t,int p){
	if(a[p].left>=l&&a[p].right<=r){
		a[p].lazy+=t;
		a[p].sum+=(a[p].right-a[p].left+1)*t;
	}else{
		push_down(p);
		int mid=(a[p].left+a[p].right)/2;
		if(l<=mid)add(l,r,t,2*p);
		if(r>mid)add(l,r,t,2*p+1);
		a[p].sum=update(p);
	}
	return;
}
ll sum(int l,int r,int p){
	if(a[p].left>=l&&a[p].right<=r)return a[p].sum;
	push_down(p);
	ll v=0,mid=(a[p].left+a[p].right)/2;
	if(l<=mid)v+=sum(l,r,2*p);
	if(r>mid)v+=sum(l,r,2*p+1);
	return v;
}

P3373 【模板】线段树 2

本题增加了一个区间乘的操作,关键在于如何记录加和乘的信息,将其下传给子节点。

我们发现一个 \(tag\) 难以维护,于是我们定义两个 \(tag\),分别是 \(mul\) 和 \(add\)。代表的意义是「整个区间先乘了 \(mul\),然后加了 \(add\)」。

  • 如果区间加 \(k\):此时整个区间先乘了 \(mul\),然后加了 \(add\),最后加了 \(k\),等价于整个区间先乘了 \(mul\),然后加了 \(add+ k\)。

所以我们直接把 \(k\) 加到 \(add\) 里,同时更新 \(sum\)。

  • 如果区间乘 \(k\):此时整个区间先乘了 \(mul\),然后加了 \(add\),最后乘了 \(k\),等价于整个区间先乘了 \(mul\times k\),然后加了 \(add\times k\)。

所以令 \(mul\to mul\times k,add\to add\times k\)。

时间复杂度 \(O(n\log n)\)。

点击查看代码
void push_down(ll p,ll ls,ll rs){
    if(a[p].tag2!=1){
        a[ls].tag2=(a[ls].tag2*a[p].tag2)%mod;
        a[rs].tag2=(a[rs].tag2*a[p].tag2)%mod;
        a[ls].tag1=(a[ls].tag1*a[p].tag2)%mod;
        a[rs].tag1=(a[rs].tag1*a[p].tag2)%mod;
        a[ls].sum=(a[ls].sum*a[p].tag2)%mod;
        a[rs].sum=(a[rs].sum*a[p].tag2)%mod;
        a[p].tag2=1;
    }
    if(a[p].tag1){
        a[ls].tag1=(a[ls].tag1+a[p].tag1)%mod;
        a[rs].tag1=(a[rs].tag1+a[p].tag1)%mod;
        a[ls].sum=(a[ls].sum+((a[ls].r-a[ls].l+1)*a[p].tag1)%mod)%mod;
        a[rs].sum=(a[rs].sum+((a[rs].r-a[rs].l+1)*a[p].tag1)%mod)%mod;
        a[p].tag1=0;
    }
}

P1471 方差

我们先思考区间平均数如何做。显然,如果我们可以快速求出区间和,然后除以区间长度就可以了,就是线段树1。

对于区间方差,我们推一下式子

\[\begin{aligned} s^2&=\frac{1}{n}\sum\limits_{i=1}^n\left(A_i-\overline A\right)^2\\ &=\frac{1}{n}\sum\limits_{i=1}^n\left(A_i^2-2A_i\overline A+\overline A^2\right)\\ &=\frac{1}{n}\sum\limits_{i=1}^nA_i^2-2\overline A\times \overline A+\overline A^2\\ &=\frac{1}{n}\sum\limits_{i=1}^nA_i^2-\overline A^2 \end{aligned} \]

显然,我们只需要维护 \(\sum\limits_{i=1}^nA_i\) 和 \(\sum\limits_{i=1}^nA_i^2\)。前者好维护(下文令其为 \(sum\)),但后者(下文令其为 \(exsum\))在区间加情况下不易维护,我们在推再下式子。

\[\begin{aligned} \sum\limits_{i=1}^n(A_i+k)^2-\sum\limits_{i=1}^nA_i^2 &=\sum\limits_{i=1}^n\left(A_i^2+2A_ik+k^2\right)-\sum\limits_{i=1}^nA_i^2\\ &=\sum\limits_{i=1}^nA_i^2+2k\sum\limits_{i=1}^nA_i+nk^2-\sum\limits_{i=1}^nA_i^2\\ &=2k\sum\limits_{i=1}^nA_i+nk^2\\ &=2k·sum+nk^2 \end{aligned}\\ \]

具体来说,如果其父节点下传懒标记 \(tag\) 给子节点 \([l,r]\),则其子节点

\[exsum'=exsum+2·tag·sum+(r-l+1)\times tag^2 \]

这样只用一个 \(tag\) 就可以维护两个变量了。

权值线段树

就是线段树维护值域。

P1774 最接近神的人

我们知道,冒泡排序的过程会进行 \(n-1\) 次循环,每次从前往后枚举 \(p\),遇到 \(a_p>a_{p+1}\) 就交换着两个数,最后序列就会变得有序,我们就可以得出结论

在一个序列列 \(A\) 中,定义一个二元组 \((i,j)\) 为“逆序对”,必须满足 \(i<j\) 且 \(A_i>A_j\)

进行一种操作,交换序列中相邻的两个元素。而用最少的,使原序列变成不下降序列的的次数即为这个序列中逆序对的个数

如何快速求解逆序对问题?

我们从后往前枚举 \(i\),对于以 \(i\) 开头的逆序对的个数,就是存在多少 \(j\) 使得 \(i<j,A_i>A_j\)。我们使用一个权值数组 \(val\),\(val_k\) 表示 \(k\) 在 \([i+1,n]\) 中的出现次数。

那么以 \(i\) 开头的逆序对的个数即为 \(\sum\limits_{l=1}^{A_i-1}val_l\),因为此时 \(val\) 数组中的所有数下表均大于 \(i\),只要满足小于 \(A_i\) 的条件即可。

求值完之后可以修改 \(val\) 数组,时间复杂度 \(O(n^2)\)。可以用线段树代替数组将复杂度优化到 \(O(n\log n)\)。

P1637 三元上升子序列

介绍两种做法。

1. 枚举中间数:

我们枚举中间数 \(j\),求两个数组,分别是 \(le_j\) 和 \(ri_j\)。

\(le_j\):存在多少 \(i\),使得 \(i<j,A_i>A_j\)。

\(ri_j\):存在对少 \(k\),使得 \(j<k,A_j>A_k\)。

实质上是两次逆序对。由乘法原理可得答案为

\[\sum\limits_{k=1}^nle_k\times ri_k \]

2.逐步递推:

我们定义 \(f_{i,j}\) 表示以 \(i\) 结尾的 \(j\) 元上升子序列。根据乘法原理可得

\[f_{i,j}=\sum\limits_{k=1}^{i-1}f_{k,j-1}[A_k<A_j] \]

初始化任意 \(f_{i,1}=1\)。我们逐步递推,本题只需推到出所有 \(f_{i,3}\)。这种做法可以推广到 \(k\) 元上升子序列,时间复杂度 \(O(kn\log n)\)。

P6186 [NOI Online #1 提高组] 冒泡排序

如果对于一个数 \(p_j\) 存在 \(i<j,p_i>p_j\),那么这轮冒泡排序无论如何都会使 \(p_j\) 被交换,在 \(p_j\) 之前比 \(p_j\) 大的数只会消失一个。

换言之,令 \(f_j\) 表示以 \(j\) 结尾的逆序对数量,在进行 \(k\) 轮冒泡排序后 \(f_j'=\max\{0,f_j-k\}\)。

而交换两个数无非对两个数的 \(f_j\) 造成影响,我们预处理出 \(f_i\),转换题意。

你需写一个数据结构维护 \(f\),支持两种操作。

  • 给定 \(k\),求出 \(\sum\limits_{i=1}^n{\max\{0,f_i-k}\}\)

  • 给定 \(x\) 和 \(t\),令 \(f_x\to f_x+t,t\in \{1,-1\}\)

显然,每次询问中 \(f_i\le k\) 的 \(f_i\) 不会在答案中有贡献。我们令 \(cnt_x\) 表示存在多少个 \(i\) 使得 \(f_i=x\)。则所有 \(f_i>k\) 的 \(f_i\) 的和即为 \(\sum\limits_{x=k+1}^ncnt_x\times x\)。因为这些数每个数都减去 \(k\),所以减去 \(\sum\limits_{x=k+1}^ncnt_x\times k=k\sum\limits_{x=k+1}^ncnt_x\)。

单点修改 \(f_i\) 就是单点修改 \(cnt_x\)。问题变成区间查询 \(\sum\limits_{x=l}^rcnt_x\times x,\sum\limits_{x=l}^rcnt_x\)。

可以用线段树快速维护。时间复杂度 \(O(n\log n)\)。

特殊维护方法

P4513 小白逛公园

直接维护显然无法做到,不过可以分开来维护。

思考区间 \([l,r]\) 的最大子段在那个位置,无非三种

  • 最大子段在 \([l,mid]\) 中:即左节点的最大子段。

  • 最大子段在 \([mid+1,r]\):中,即右节点的最大子段。

  • 包含 \(mid,mid+1\):即最大子段可分成两部分,分别是 \([L,mid]\) 和 \([mid+1,R]\),\([L,R]\) 即表示最大子段

第三种情况下,因为 \([L,R]\) 最大,所以 \([L,mid]\) 是左节点最大后缀,\([mid+1,R]\) 则是右节点最大前缀。

所以我们还要维护区间最大前后缀,无非两种情况,我们就最大前缀来讲,假设区间 \([l,r]\) 的最大前缀是 \([l,R]\)

  • \(R\le mid\):即左子节点最大前缀。

  • \(R > mid\):将最大前缀分为 \([l,mid],[mid+1,R]\),前一个是左子节点区间和,后一个是右子节点最大前缀。

我们同时维护区间和,区间最大前缀,区间最大后缀,区间最大子段,下文分别用 \(sum,lmax,rmax,mmax\) 来表示,\(p,l,r\) 分别是一个节点和他的左右两个子节点。则

\[sum_p=sum_l+sum_r \]

\[lmax_p=\max\{lmax_l,sum_l+lmax_r\} \]

\[rmax_p=\max\{rmax_r,sum_r+rmax_l\} \]

\[mmax_p=\max\{mmax_l,mmax_r,rmax_l+lmax_r\} \]

P1558 色板游戏

注意到虽然是区修,但颜色很少,所以可以开 \(30\) 颗线段树,每颗线段树代表一种颜色。每次修改和查询都跑三十遍就好了。

但显然不够优秀,我们发现题目只关注颜色是否出现,首次启发,对于每个区间 \([l,r]\),压缩一个二进制串,如果这个串第 \(i\) 个数为 \(1\),则表示这种颜色在区间中出现,\(0\) 则反之。

显然易见,该信息具有区间可加性,\(\text{push\_up}\) 用或运算就可以完成。

线段树提高

动态开点

线段树在维护值域时会有一个痛点,如果值域很大,把线段树建出来会空间超限。针对这个问题,我们可以使用动态开点的技巧,即在使用时建出要使用的节点。

P5459 [BJOI2016] 回转寿司

求出 \(a\) 的前缀和数组 \(S\),则 \(\sum\limits_{i=l}^ra_i=S_r-S_{l-1}\)。我们枚举 \(S_r\),即求出

\[L\le S_r-S_{l-1}\le R \]

化简的

\[S_r-R\le S_{l-1}\le S_r-L \]

求出存在多少 \(l-1(l>1)\),满足 \(l-1< r\) 且 \(S_{l-1}\in[S_r-R, S_r-L]\),显然可以使用权值线段树解决。

数据最大可以达到 \(10^{10}\),使用动态开点,则树高可达到 \(34\),一次修改最多增加 \(34\) 个节点,数组开 \(3.4\times 10^6\) 大小足矣。

ll New(){
    a[++tot]=node{0,0,0};
    return tot;
}//动态新建节点
void insert(ll p,ll l,ll r,ll x){
    if(l==r)return a[p].sum++,void();//到达最底部
    ll mid=(l+r)>>1;
    if(x<=mid){
        if(!a[p].lc)a[p].lc=New();//插入时不处在,动态开点
        insert(a[p].lc,l,mid,x);
    }else if(x>mid){
        if(!a[p].rc)a[p].rc=New();
        insert(a[p].rc,mid+1,r,x);
    }
    a[p].sum=a[a[p].lc].sum+a[a[p].rc].sum;
}
int ask(ll p,ll l,ll r,ll L,ll R){
    if(L<=l&&r<=R)return a[p].sum;
    ll mid=(l+r)>>1,cnt=0;
    if(L<=mid)cnt+=(!a[p].lc)? 0:ask(a[p].lc,l,mid,L,R);//查询时不存在,直接返回0.
    if(R>mid)cnt+=(!a[p].rc)? 0:ask(a[p].rc,mid+1,r,L,R);
    return cnt;
}

标记永久化

在写线段树的过程中,有时我们很难 \(\text{push\_up}\),例如二维线段树或树套树,无法再较短时间内 \(\text{push\_up}\)。或有时一个节点同时是多个节点的子节点,例如可持久化线段树,我们无法懒标记下传。

针对一些特殊的信息维护,我们可以使用“标记永久化”这种技巧,即给节点打上标记后不在下传,而是在查询时,将该节点到根节点路径上所有节点的标记累加起来。例如区间最大值,区间和等等。

这样做既可以解决无法使用懒标记的问题,还可以进一步优化常数,一举两得,缺点是必须要求打上标记的结果与打上标记的顺序无关。

势能线段树

P4145 上帝造题的七分钟 2 / 花神游历各国

思考一个问题,如果一个数 \(x(x>2)\) 不断执行 \(x\to x^2\)。显然 \(x\) 的增长成指数级,相反的,如果一个数 \(x\) 不断的执行 \(x\to \lfloor\sqrt x\rfloor\) 直至 \(x\) 为 \(1\)。那么操作次数理论在 \(\log n\) 这个级别,实际上更少。

这启发我们对于每个不为 \(1\) 的数暴力开平方,则修改操作的时间复杂度就是 \(O(n\log n)\),我们要同时维护区间和,很容易想到线段树。

如果对区间 \([l,r]\) 中每个数均开方,但区间内每个数均为 \(1\),开平方就没有意义(修改后任何值无变化),因此维护区间最大值,只要这个值大于 \(1\),就将其暴力修改。

这样看似时间复杂度 \(O(n^2)\),实际上只有 \(O(n\log n)\),这种特殊的分析方法叫做势能分析法

CF438D The Child and Sequence

一个结论:\(x \bmod p< \frac{x}{2}(x\ge p)\)。证明如下:

  • \(p\le \frac{x}{2}\)

因为 \(x\bmod p <p\),所以 \(x\bmod p<\frac{x}{2}\)

  • \(\frac{x}{2}<p\le x\)

变形可得 \(2p>x\),则 \(x\bmod p=x-p\),因为 \(\frac{x}{2}<p\),所以 $x\bmod p<\frac{x}{2} $

维护区间最大值,照样做就行。

虽然有单点修改,但不同的数最多仍只有 \(10^5\) 级别个,不影响时间复杂度。

扫描线

面积并,周长并以及二维数点问题。

P5490 【模板】扫描线

经典面积并。

直接算无从下手,不过我们可以快速分割图形。将一坨分成若干矩形分开来算(依据所有矩形的左右边所在直线划分,下图省略了重复的线)

分割图形

然后维护一根线,从左边走到右边。这就是扫描线求面积并的核心思想。

扫描线

我们把一个矩形 \((x_1,y_1),(x_2,y_2)\) 分成两个四元组 \((x_1,y_1,y_2,1),(x_2,y_1,y_2,-1)\) 分别表示矩形的左右两边。

当扫描线经过一个四元组时,扫描线在矩形并中的部分可能会增加。具体说,如果当前扫描线遇到一个 \((x_1,y_1,y_2,1)\) 的四元组,且扫描线中不包含 \((y_1,y_2)\) 这一部分,那扫描线所截线段长就会加上这一部分;如果当前扫描线遇到一个 \((x_1,y_1,y_2,-1)\) 的四元组,且扫描线中包含 \((y_1,y_2)\) 这一部分,那扫描线所截线段长就会减去这一部分。

我们把所有四元组的 \(y\) 放在一起排序,则 \(c_i\) 表示 \(y_i\sim y_{i-1}\) 这一段区间,如下图。

这

则遇到四元组的操作可以写为区间加,这样就可以用线段树维护截线长了。

然后就做好了,时间复杂度 \(O(n\log n)\)。

for(int i=1;i<=2*n-1;i++){
	ll L=lower_bound(raw+1,raw+1+tot,b[i].y1)-raw;
	ll R=lower_bound(raw+1,raw+1+tot,b[i].y2)-raw;
	if(L>R)swap(L,R);
	add(1,L,R-1,b[i].k);
    ans+=a[1].dat*(b[i+1].x-b[i].x);
}

P1972 [SDOI2009] HH的项链

经典二维数点。

记一个数 \(a_i\) 上一次出现的位置为 \(pre_i\)(\(a_i\) 第一次出现,则 \(pre_i=0\))。

一个数在区间 \([l,r]\) 中可以出现很多次,我们只关心最后边的个一个,如果存在 \(a_i\) 满足 \(i\in[l,r],pre_i\in[0,l-1]\),则这个数在区间中出现过。

转化问题,我们令 \((i,pre_i)\) 为坐标系中的一个点,则求出 存在多少点在 \((l,0),(r,l-1)\) 所成的矩形之间。

因为可差分,且容易差分,我们将其分为两个询问的差。用扫描线扫,同时维护扫过的点。

然后写完了。

二维线段树

P3437 [POI2006] TET-Tetris 3D

打算写,鸽一鸽。

线段树二分

P3369 【模板】普通平衡树

P8765 [蓝桥杯 2021 国 AB] 翻转括号序列

打算写,鸽一鸽。

线段树合并

P4556 [Vani有约会] 雨天的尾巴 /【模板】线段树合并

P3224 [HNOI2012] 永无乡

没学,不会写。

线段树分裂

P5494 【模板】线段树分裂

没学,不会写。

可持久化线段树

P3919【模板】可持久化线段树 1(可持久化数组)

没学,不会写。

主席树

P3834 【模板】可持久化线段树 2

没学,不会写。

线段树分治

P5787 二分图 /【模板】线段树分治

没学,不会写。

树套树

P3380 【模板】树套树

没学,不会写。

李超线段树

P4097 【模板】李超线段树 / [HEOI2013] Segment

没学,不会写。

线段树好题

好题不会写。

线段树延伸

树状数组 \(\text{and}\) ST 表

P3374 【模板】树状数组 1

P3372 【模板】线段树 1

P4514 上帝造题的七分钟

P3865 【模板】ST 表

打算写,鸽一鸽。

zkw 线段树

P3372 【模板】线段树 1

线段树优化建图

P5025 [SNOI2017] 炸弹

没学,不会写。

线段树优化 DP

P9871 [NOIP2023] 天天爱打卡

P2605 [ZJOI2010] 基站选址

没学,不会写。

猫树

没学,不会写。

珂朵莉树

没学,不会写。

标签:limits,线段,节点,sum,区间,ll
From: https://www.cnblogs.com/zuoqingyuan/p/18366958

相关文章

  • 洛谷 P3919 可持久化线段树 1 之主席树模板(初级)
    洛谷P3919题解传送锚点摸鱼环节【模板】可持久化线段树1(可持久化数组)题目背景UPDATE:最后一个点时间空间已经放大2021.9.18增添一组hack数据by@panyf标题即题意有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集)题目描述如题,你需要维护这......
  • 可持久化线段树(主席树)
    区间第k大/小问题洛谷P3834好吧,区间问题,考虑线段树でも,线段树能求解的问题须是大问题的解可以从小问题的解合并而来,显然,第k大/小问题不满足,不能直接用一颗树解决考虑用多颗树怎么想到的?我要是想到了我就成主席了首先,烧烤一下如何用线段树求1-i的第k小值烧烤ing……以......
  • 刍议线段树 3 (扫描线)
    扫描线扫描线是一种另外的思想,只是其中会运用到线段树以求优化。所以不要将扫描线简单的并为线段树的一个小拓展。例题:https://www.luogu.com.cn/problem/P5490大意:求\(n\)个四边平行于坐标轴的矩形的面积并。思路:纵向分割图形我们考虑把这些纵向矩形分割。那么,总面积就......
  • 线段树模板,洛谷原题P3373
    线段树区间乘、加,范围求和,QWQ原题#include<bits/stdc++.h>#definePIIpair<int,int>#defineintlonglong#defineDBdoublenamespaceFastIO{ inlineintread(intMOD,int&ret){ charch=getchar();intngtv=1; if(MOD==0){while(ch<&#......
  • D46 2-SAT+线段树优化+二分 [ARC069F] Flags
    视频链接: [ARC069F]Flags-洛谷|计算机科学教育新生态(luogu.com.cn)//D462-SAT+线段树优化+二分O(nlognlogv)#include<iostream>#include<cstring>#include<algorithm>usingnamespacestd;#definemid((l+r)>>1)#definels(u<<1)#definer......
  • leetcode线段树(2940. 找到 Alice 和 Bob 可以相遇的建筑)
    前言经过前期的基础训练以及部分实战练习,粗略掌握了各种题型的解题思路。现阶段开始专项练习。描述给你一个下标从 0 开始的正整数数组 heights ,其中 heights[i] 表示第 i 栋建筑的高度。如果一个人在建筑 i ,且存在 i<j 的建筑 j 满足 heights[i]<heig......
  • 算法笔记——可持久化线段树
    维护历史值当要修改一个节点时,把跟他有关的线段树中所有节点舍弃,并建立新节点连接.代码如下:#include<bits/stdc++.h>usingnamespacestd;constintN=1e6+5;intn,m,a[N],root[N],top;structnode{ intl,r,val;}t[N*40];intclone(intx)//新建节点{ top++; t......
  • 有关线段树的一些细节理解
    写在前面本菜鸡线段树学了好多遍但是每次写还是得很长时间有时有一个细节还要琢磨半天所以为了今后避免以上事情发生本菜鸡决定将这么长时间以来对线段树的认识汇总好日后清算模板#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=1e5;i......
  • zkw线段树
    事情的起因是我某天吃晚饭时打算找个电子榨菜,然后b站搜索线段树,看到了一个名叫zkw线段树(即非递归线段树),由于不是面向Oier的,所以饭后我又找了几个博客看,现在写下心得记录(其实只是不想在书签留3个位置给线段树)为什么要学习非递归线段树,这个问题大部分博客解释为普通线段树......
  • 『线段树合并』Day7
    颓了一天了。md虽然还没有过线段树合并板题,但早就用过了。注意,单次合并复杂度是\(O(n\logn)\)的,但是一直合并,保证最终共有\(n\)个元素的话,总时间复杂度也是\(o(n\logn)\)的。不要理解成单次\(\logn\)。一个人千万不能忘记自己的初心,有时候需要静下心来想一想自己到底......