线段树笔记

线段树是二叉搜索树,每个节储存一个区间的信息。,通常适合用来处理区间的问题

线段树的基本思想是二分,线段树的核心是懒标记

1、区间修改&&区间查询

题解 P3372 【【模板】线段树 1】 - 菜鸡本菜 - 洛谷博客 (luogu.com.cn)

单点修改是区间修改的特例

2、两个懒标记
P3373 【模板】线段树 2 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

先乘后加,懒标记在pushdown过程中顺序很重要

3、扫描线

P5490 【模板】扫描线 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

扫描线可用于处理面积并。通过垂直x轴的的扫描线从图形最左向最右扫描,扫描过程中要不断维护沿y轴上的有效长度,即值域内哪些线段对计算面积有贡献,而有效长度可看作一个个有贡献的区间内的线段的和,所以有效长度可利用线段树来维护。

注意:由于数据在y轴上范围过大,所以要对数据进行离散化,有效长度也用离散线段树维护(离散线段树叶节点长度为2)

具体参考:

576 扫描线算法 线段树【计算几何】_哔哩哔哩_bilibili

4、

P4588 [TJOI2018]数学计算 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

该题用线段树来维护区间乘,这样的话根节点就是到现在为止的所有数的乘积。

由于数据过大的原因,模拟的话sum* m可能会让结果直接溢出,所以我们可以考虑所有乘数在相乘的过程中进行取模,相当于(m1*m2*m3*m4……)%mod转变为m1*m2%mod*m3%mod*m3……,即乘以次取一次模,可以用在线段树pushup的操作上。

第二个操作是去除某次乘的值,根据乘除逆运算的关系,除一个值就是将那个值置1,可以看作一次修改操作,即修改叶节点。

5、区间最大

P2471 [SCOI2007] 降雨量 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

线段树维护区间最大值

int query(int now, int l, int r, int x, int y) {
	if (x <= l && r <= y) return t[now];
	int mid = (l + r) / 2;
	int ans = 0;
	if (x <= mid) ans = query(ls(now), l, mid, x, y);
	if (y > mid) ans = max(ans, query(rs(now), mid + 1, r, x, y));
    // 注意不是 else if(y > mid) ans = max(ans, query(rs(now), mid + 1, r, x, y)), 否则有可能        
    // 会缺少对右区间的查询
	return ans;
}

须注意点:

(1)离散化:low_bound的使用,返回值就是返回第一次出现大于等于那个要查找的数的地址。

(2)输入年份先判断其降雨量是否存在,再判断两个年份(下标)是否相邻,最后再判断区间最大。

6、懒标记标记状态

P2574 XOR的艺术 - 洛谷 | 计算机科学教育新生态 (luogu.com.cnl

懒标记传递反转状态,需要反转为1,不需要为0。

7、线段树维护两值

P1471 方差 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

方差可拆成区间平方和与区间和的线性组合,所以线段树要同时维护区间平方和与区间和。

8、线段树维护区间最大线段

Glass Carving - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

线段树叶节点表示矩形内直线是否被分割,1表示未分割,0表示已分割,则统计连续1最大长度+1即为最大线段。

判断连续1最大长度时,注意最大长度可能出现一个节点所代表区间中间,即左儿子节点右端连续1长度+右儿子节点左端连续1长度,所以每个节点要维护左端最大连续1长度、右端最大连续1长度和整个区间最大连续1长度。

特判:儿子区间全为连续1,节点的左端最大连续1长度或右端最大连续1长度的维护有不同处理

P2894 [USACO08FEB] Hotel G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

线段树维护区间连续最大线段,每个节点同样要维护左端连续最大线段、中间连续最大线段、右端连续最大线段,所以懒标记的传递和向上的更新函数写法与常规不同。

此题精髓在查询,左儿子有符合线段则一直向左递归,直到左儿子不够长,进而判断左儿子与右儿子连续线段是否符合,若都不符合则向右儿子递归。

int ask(int p,int l,int r,int length)
{
	spread(p);//下放懒标记
	if(l==r)return l;//如果找到对应区间,返回左端点
	int mid=(l+r)/2;
	if(t[p*2].sum>=length)return ask(p*2,l,mid,length);
    //如果左区间即可找到足够多的房间,就在左区间找
	if(t[p*2].rmax+t[p*2+1].lmax>=length)return mid-t[p*2].rmax+1;
    //如果在中间能找到足够多的房间,答案就是左区间从右开始的最长连续区间的左端点
	else return ask(p*2+1,mid+1,r,length);
    //否则就在右边找
}

9、维护区间最大公约数

[蓝桥杯 2022 国 A] 最大公约数 - 洛谷

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值