Loading

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)\)

posted @ 2025-05-04 19:29  larsr  阅读(49)  评论(0)    收藏  举报