Tree(LHF)
没什么价值的题就没放进来。
树形背包
Pro 1
给一个树,每个点有个权值 \(b_i\),点集 \(S\) 的贡献为 \(\prod_{i\in S} b_i\)。多个询问 \((u,x)\),求出在子树 \(u\) 中所有大小为 \(x\) 的子集贡献之和。
\(x\le k\)。
Sol 1
经典树形背包,考虑分析复杂度,考虑合并两个背包,大小分别为 \(x,y\):
- \(x,y\le k\),相当于分成若干大小小于 \(O(k)\) 的块,每个块的贡献为 \(O(siz^2)\),总复杂度 \(O(\frac{n}{k}k^2)=O(nk)\)。
- \(x\le k,y>k\),合并复杂度为 \(siz_xk\),全部的 \(siz_x\) 最多为 \(O(n)\),复杂度 \(O(nk)\)。
- \(x,y>k\),这种合并最多有 \(n/k\) 次,复杂度 \(O(nk)\)。
即证明总复杂度为 \(O(nk)\)。
Pro 2
给一个树,每个点有个价值 \(a_i\) 和权值 \(b_i\),点集 \(S\) 的贡献为 \(\prod_{i\in S} b_i\)。多个询问 \((u,x)\),求出在子树 \(u\) 中所有价值和为 \(x\) 的子集贡献之和。
\(x\le k\)。
Sol 2
暴力合并为 \(O(\frac{nk^2}{\log k})\)。
NTT 合并为 \(O(nk\log k)\)。
启发式合并为 \(O(nk\log n)\)。
考虑将三个算法合并,考虑合并两个大小为 \(x,y\) 的背包:
- \(x,y\le \sqrt k\),暴力合并,复杂度 \(O(\frac{nk}{\log k})\)。
- \(x\le \sqrt k,y>\sqrt k\),启发式合并,复杂度 \(O(nk)\)。
- \(x,y>\sqrt k\),NTT 合并,复杂度 \(O(nk)\)。
总复杂度 \(O(nk)\)。
Pro 3
给定一棵 \(n\) 个点的树和 \(k\),问有多少种断边的方式使得树的每个连通块的大小都是 \(k\) 或 \(k + 1\)。 对 \(998244353\) 取模。
\(1\le k < n \le 10^5\)。
Sol 3
暴力做发现一个点背包最大为 \(\min(k, siz/k)\),平衡一下复杂度为 \(O(n^{1.5})\)。
发现如果一个子树大小小于 \(k\),那么肯定是不断边的,合并也可以 \(O(1)\) 懒标记。
有值的位置一定是一个小于 \(O(siz/k)\) 的区间,那么可以用 Pro 1 的分析方式,复杂度为 \(O(\frac{n}{k}k)=O(n)\)。
Pro 4
有一棵 \(n\) 个点的有根树,第 \(i\) 个点有一个重量为 \(b_i\),权值为 \(a_i\) 的物品,定义一组选物品的方案的权值为所选物品的权值和,要求所选物品之间不能有边相连,对于所有 \((x,i)(1\le x\le n,1\le i \le m)\),你需要求出 \(x\) 子树内所有满足选出物品重量之和为 \(i\) 的方案的权值和的最大值。
Sol 4
首先求最大值就不能使用 NTT。相邻的点不能同时选,所以不能启发式合并。
考虑重链剖分,从链低开始考虑,枚举当前点选不选,再递归轻儿子。状态数 \(T(n)=\sum_u 2^{u到根轻边数量}\),那么 \(T(n)=\max_{a_{1,\ldots,k},a_1 \ge a_i} T(a_1) + 2\sum_{i=2}^k T(a_i)\),发现 \(T(n)=n^{log_2 3}\),约等于 \(O(n^{1.5}m)\)。
考虑若 \(m\) 较小的情况,对于大小小于 \(B\) 的子树使用上面的做法 \(O(\frac{n}{B}B^{1.5})=O(nB^{0.5}m)\)。对于大于 \(B\) 的子树直接暴力合并,复杂度 \(O(\frac{n}{B}m^2)\)。\(B\) 取 \(m^{2/3}\),总复杂度 \(O(nm^{4/3})\)。
Pro 5(链分治)
有一棵 \(n\) 个点的有根树,第 \(i\) 个点有一个重量为 \(1\),权值为 \(a_i\) 的物品,定义一组选物品的方案的权值为所选物品的权值乘积,要求选的物品对应的点构成一个包含根节点的连通块。求出所有连通块大小为 \(i\) 的方案的权值之和。
\(n\le 10^5\)。
Sol 5
链分治=树链剖分/全局平衡二叉树+NTT?
全局平衡二叉树一下,记录左端点和右端点是否选了,NTT合并即可?复杂度 \(O(n\log^2n)\)。
长链剖分&树上领域查询
以下的领域查询是基于交换半群的,可以理解为若干数相乘模 \(p\) 的结果,\(p\) 不一定为质数,,即不能使用逆元。
矩阵查询
对于下面的形状的平面,求一个矩阵的信息,但矩阵下面没有边,即矩阵限制为 \(a\le x\) 和 \(y\le b\)。
O-O-O-O-O
O-O
O-O-O-O
O-O-O
O
O
找到这个矩阵的最小的一个 \(x(a\le x)\) 使得 \((x,b)\) 存在点,那么预处理出 \((x,b)\) 左下方的结果,再加上 \([a,x-1]\) 行的结果。
在后面的操作中斜线上的点(即 P)是该链上的点,P 后面跟的是该点的轻子树合并后的结果,那么矩阵查询相当于查询距离某个点 \(\le d\) 的点的信息,不过是在子树内的。
P-O-O-O-O
P-O
P-O-O-O
P-O-O
P
P
跳链
考虑询问 \((x,d)\) 为距离 \(x\) 小于等于 \(d\) 的点的领域。如果 \(h_x + 1\le d\)(\(h_x\) 是 \(x\) 所在链的长度),那么 \((fa_x,d-1)=(x,d)\),这样就可以一直跳链。
如果 \(z\) 是 \(x\) 的第一个满足 \(d\le 2h_z\) 的祖先,可以发现在 \(x\) 跳到 \(z\) 的点 \(y\) 之前都满足 \(2h_y+1\le d\), 那么 \(h_y+1\le d-1-h_y\le d+dep_y-dep_x=d'\)。所以满足之前的跳链操作。
那么要解决满足 \(d\le2h_x\) 的领域 \((x,d)\),直接对于链顶预处理出该子树外距离 \(\le 2h_x\) 的点的信息,发现容易解决,复杂度线性。
如何找到这个点 \(z\) 呢?可以找到这个链,然后找到 lca 即可。开 \(1\sim n\) 的栈,dfs 时如果遇到链顶则将该点加入 \(1\sim h_x\) 的栈中,回溯时再弹出,找到点 \(x\) 直接找 \(\lfloor d/2\rfloor\) 的栈顶即可。不过这个是离线做法。
树上 k 级祖先
考虑 \(O(n)-O(1)\) 做法。
\(O(n\log n)-O(1)\) 做法瓶颈在于预处理每个点 \(\log n\) 个祖先关系,一个点的 k 级祖先可以转化为该子树的一个叶子的祖先?那么可以只预处理叶子的 \(\log n\) 个祖先关系,复杂度 \(O(lef\log n)\)。
对于所有极大的大小小于 \(B\) 的子树可以先去掉,剩下的树直接按上面的处理即可,复杂度 \(O(\frac{n}{B}\log n)\),对于被删去的树形态最多有 \(\frac{\binom B{2B}}{B}\) 种,暴力处理所有形态的树,复杂度 \(O(\binom B{2B})\)。\(B\) 设置成 \(\frac{1}{2}\log n\sim \log n\) 比较合适,总复杂度 \(O(n)\)。
序列前驱问题
给一个序列 \(a_1\ldots a_n\) 和若干询问 \((x,k)\) 求最大的 \(y\) 满足 \(y\le x\) 且 \(k\le a_y\)。\(S=\sum a_i\),给出 \(O(n+S)-O(1)\) 做法。
对于 \(i\),建出点 \((i,1)\ldots (i,a_i)\),对于 \((x,y)\) 连向 \((z,y+1)\),\(z\) 为存在 \((z,y+1)\) 的最大 \(z\),若不存在则为根,那现在建出来一个森林,询问就相当于求 \((x,1)\) 的 \(k-1\) 级祖先,直接利用树上 \(k\) 级祖先做法即可。
在线跳链
直接利用序列前驱问题的做法即可,只不过把序列变成树了。
Other Problem
Pro 1
有一棵 \(n\) 个点的树,每个点都有一个集合,初始均为空,现在在上面做 \(m\) 次操作。第 \(i\) 次操作给定 \(x_i,y_i\),并将 \(x_i,y_i\) 路径上的所有点的集合中都加入 \(i\)。 然后询问有多少对点满足它们的集合交非空。
\(1\le n,m\le10^5\)。
Sol 1
考虑对于覆盖 \(i\) 的路径 \(x_i,y_i\) 建出虚树,那么虚树大小就是和 \(i\) 的集合交非空的点数,对于虚树上的点 \(a_1,\ldots a_k\) 按照 dfs 序排序,那么虚树点数就是 \(\frac{dis(a_1,a_k)+\sum_i dis(a_i,a_{i+1})}{2}\)。复杂度 \(O(n\log^2 n)\)。
Pro 2
给定一棵 \(n\) 个点的树以及参数 \(d\),考虑一个 \(n\) 个点的新图 \(G\),\(G\) 中 \(x,y\) 有连边当且仅当 \(x,y\) 在原树上的距离 \(\le d\)。 现在有 \(Q\) 次询问,每次询问给定 \(l,r\),求只保留 \(G\) 中编号为 \([l, r]\) 的点时形成的连通块数量。
\(n\le 3\times 10^5,Q\le 6 \times 10^5\)。
Sol 2
考虑使用钦定代表元做法。
按照 bfs 序,将点排列为 \(p_1,\ldots,p_n\)。考虑到以下性质:
\(x<y<z\),如果 \(dis(x,z),dis(y,z)\le d\),那么 \(dis(x,y)\le d\)。
那么一个连通块的代表元就是排序 \(p\) 位置最小的点。求出 \(u\) 作为代表元出现的条件 \(l\le L \le i \le r\) 中的 \(L\),\(L\) 可以点分治求出,复杂度 \(O(n\log^2 n)\)。
Pro 3
给定一棵 \(n\) 个点的树,每个点有一个颜色,有 \(Q\) 次查询。查询操作给定参数 \(l,r,x\),求只保留编号为 \([l, r]\) 的点之后 \(x\) 所在的连通块的不同颜色数。
\(n,Q\le 10^5\)。
Sol 3
直接点分治,查询当前根是否在 \(x\) 的连通块内,如果在直接询问,2-side 矩形数颜色即可。\(O(n\log^2n+Q\log n)\)。
Pro 4
给定一棵 \(n\) 个点的树,有 \(Q\) 次询问,每次给定 \(l, r, x\),求有多少对 \((i, j)\) 满足 \(l \le i < j \le r\), \(lca(i, j) = x\)。
\(n,Q\le 2\times 10^5\)。
Sol 4
大致的计数思路可以是 \(|S-\cup_{l\le i \le r}i\notin tree_x|^2-\sum_{v\in son_x} |S\cap tree_v|^2\) 。
如果 \(d_x\le \sqrt n\),直接暴力枚举儿子,然后二维数点即可,数一次复杂度是 \(O(1)\) 的。
否则先处理前 \(\sqrt n\) 大的子树,那么剩下子树的点考虑提前预处理出来,按照点编号排序,对于在不同子树的点给它们染色即可,那么可以变成一个莫队处理即可。发现每个点只会出现在一个祖先的处理序列里面,所以总复杂度 \(O(n\sqrt n)\)。
Pro 5
给定一颗大小为 \(n\) 的有根树,每个点有权值 \(a_i,b_i\),每个点的父亲都小于当前点编号。定义一个点的 \(c\) 值为其所有没被标记的儿子的 \(b\) 值加上该点的 \(a\) 值。初始整棵树的点都没被标记,每次计算出所有点的 \(c\) 值,然后选择没被标记的点中 \(c\) 值最大的那个并标记,如果有多个则取编号最大的。
现在有 \(Q\) 次操作,每次询问形式为如下两种之一:
- 给定 \(x, A, B\),更改 \(x\) 的 \(a, b\) 值为 \(A, B\)。
- 给定 \(x, y\),询问如果进行题目中所描述的标记过程,问 \(x\) 是否比 \(y\) 先被标记。
\(1\le n,Q\le 2\times 10^5,1\le a_i,b_i\le10^8\)。
Sol 5
考虑维护 \(g_u\) 为当点 \(u\) 被标记时它的 \(c\) 值,一个点的 \(g_u\) 只于 \(b_{son_u}\) 和 \(g_{son_u}\) 有关,可以搞个权值线段树维护这个东西。暴力修改复杂度 \(O(\sum dep\log V)\)。
可以重链剖分,对于一条链维护线段树,对于一个区间 \([l,r]\) 维护 \(f_{0/1},p\),\(f_{0,1}\) 为 \(r\) 的重儿子比 \(r\) 先/后选时 \(g_l\) 的值,\(p\) 为 \(r\) 的重儿子比 \(r\) 后选 \(g_r\) 的值。复杂度 \(O(n\log n\log V)\)。