线段树分治学习笔记

线段树分治

线段树分治是一种可以离线处理带撤销问题的常用手段。一般而言,题目中加入操作很好维护,但删除操作不好维护,这时可以对时间维建线段树,把每一个操作加入其存在时间段对应的线段树节点上,然后处理所有询问,进入一个节点时将这个节点里的操作加入,递归左右儿子,然后撤销这一次做的操作,在线段树根节点处统计答案。因为要支持可以撤销操作,因此一般是将所有操作的逆操作做一遍或者配合可撤销并查集等可撤销数据结构使用。

线段树分治虽然只能离线,但是可以解决一些“伪在线”的题目,比如如果一次操作合法就进行,否则不进行,这种问题可以在处理叶子结点 \([l,l]\) 时,如果合法就新加入一个 \([l+1,r]\) 的操作,而这个操作对当前并不会造成影响,因此这样做是正确的。

一些例题:

动态加删边和二分图判定

判断二分图的方式有很多,一个比较有拓展性的方法是拓域并查集,即如果存在 \((x,y)\),那么就将 \(x,y+n\)\(x+n,y\) 所在并查集合并,如果 \(x,y\) 已经在同一个并查集里,那么就说明原图不是二分图(因为这样就意味着出现了奇环),而并查集又是可以撤销的,于是可以直接用线段树分治套可撤销并查集。

[省选联考2023] 人员调度

把原来的操作改成:树上每个点先有 \(siz_x\) 的容量,每加一个工厂就把 \(x\) 到根路径上的容量减 1,如果加入后有 -1 了就把深度最大的为 -1 的点的子树里贡献最小的工厂的贡献减掉,这样就可以很好用树剖维护。我们发现不好处理删除操作,于是考虑按时间轴分治,这样就可以很好解决删除的问题。

瓶颈在于复杂度是 \(O(n\log^3n)\) 的,于是就考虑使用全局平衡二叉树把树剖降成单 log,这样就是 \(O(n\log^2n)\) 的。

P9130 [USACO23FEB] Hungry Cow P

题意:Bessie 很饿,每天晚饭如果有干草就会吃 \(1\) 份,没有就不吃,初始没有干草。

每天早上 Farmer John 会给它送若干干草,设第 \(k\) 天送 \(a_k\) 份干草,初始时 \(a_k=0\),表示该天不送干草。

\(q\) 次操作,每次给出 \(x,y\),表示将 \(a_x\) 改成 \(y\),请将在此时 Bessie 有干草吃的 日期编号 求和并输出。对 \(10^9+7\) 取模。

思路:很类似楼房重建的 trick。

我们先离散化,然后考虑用线段树维护。每个节点维护 4 个信息,总共匹配了多少个值,总共向右超出了多少个值,匹配的答案是多少,左区间超出部分的答案。

在合并时,有两种情况,一种是左边超出部分在右区间依然超出,此时右区间被填满了;否则就在右区间线段树上二分,求出最后一个左区间超出部分的位置。

实际上直接线段树分治然后用可持久化代替撤销也可以过。

CF938G Shortest Path Queries

题意:给出一个连通带权无向图,边有边权,要求支持 \(q\) 个操作:

\(1\) \(x\) \(y\) \(d\) 在原图中加入一条 \(x\)\(y\) 权值为 \(d\) 的边

\(2\) \(x\) \(y\) 把图中 \(x\)\(y\) 的边删掉

\(3\) \(x\) \(y\) 表示询问 \(x\)\(y\) 的异或最短路

思路:首先考虑没有修改的做法。我们可以求出一棵生成树,然后把非树边形成的环加入线性基,然后求两点路径异或和和线性基可以异或得到的最小值。

有了加删边,我们就可以考虑用线段树分治,实时维护当前的联通块中每个点到根的异或和,同时维护线性基就可以了。

CF576E Painting Edges

题意:给定一张 \(n\) 个点 \(m\) 条边的无向图。

一共有 \(k\) 种颜色,一开始,每条边都没有颜色。

定义合法状态为仅保留染成 \(k\) 种颜色中的任何一种颜色的边,图都是一张二分图。

\(q\) 次操作,第 \(i\) 次操作将第 \(e_i\) 条边的颜色染成 \(c_i\)

但并不是每次操作都会被执行,只有当执行后仍然合法,才会执行本次操作。

你需要判断每次操作是否会被执行。

思路:“伪在线” 线段树分治模版题。

我们可以维护 \(k\) 个拓展域并查集来判断是否满足条件。我们递归到叶子的时候,如果当前操作可以执行,那么就加入这个操作,新加入的操作是不会影响前面的情况的,我们相当于是可以在线添加操作。

CF603E Pastoral Oddities

题意:依次加边,判断是否存在一个边集满足每个点的度数均为奇数,最小化最大边权。

思路:首先可以发现充要条件:每个联通块大小都是偶数。

因为要最小化最大边权,这很像最小瓶颈生成树,可以用 Kruskal 算法,于是如果不带修改的话可以把所有边从小到大加入,维护奇联通块个数。

带加边可以考虑用线段树分治。容易发现,如果一条边当前没用了,以后也不会再用上,于是每条边做贡献的是一段区间。考虑先往右递归,递归到叶子就可以求出一条边是否不会再做贡献了,这样就可以求出一条边做贡献的区间。

posted @ 2024-02-12 21:39  Xttttr  阅读(99)  评论(0编辑  收藏  举报