Description
题目链接:Codeforces 916E
给你一棵有根树标号为 $1\sim n$,每个点都有一个权值 $a_i$。初始时根为 $1$,接下来有 $q$ 次操作,操作分为以下 $3$ 种:
1 x
:将整棵树的根变为节点 $x$。2 x y k
:把 $x,y$ 的 $\text{LCA}$ 为根的子树中的所有点的权值增加 $k$。3 x
:查询以 $x$ 为根的子树中的节点的权值和。
数据范围:$1\le n,q\le 10^5$,$-10^8\le a_i,k\le 10^8$
Solution
如果没有换根操作,那么我们只需要对这棵树的 $\text{DFS}$ 序建立线段树,支持区间修改和区间查询。
接下来考虑换根操作。此时我们显然不能真的把根换掉,根只能一直为 $1$ 节点,而是要对根和操作的节点的关系进行分类讨论!
由于操作 $2$ 和操作 $3$ 在位置关系分析上的本质是相同的,所以我们只需要考虑位置关系和如何求 LCA 即可。
位置关系
设当前整棵树的根节点为 $R$,询问的子树根节点为 $X$,那么我们可以发现这两者存在以下 $3$ 种关系。
对于每种位置关系的图示,$R$ 和 $X$ 均标记在节点上,蓝色的节点表示需要被操作的节点。
-
如果 $R$ 就是 $X$:
此时整棵树的所有节点都需要被操作。
-
如果 $R$ 不在 $X$ 的子树内:
此时我们可以发现 $X$ 这棵子树的形态与原图的形态一致,所以只要对以 $1$ 为根节点时的子树 $X$ 进行操作即可。
-
如果 $R$ 位于 $X$ 的子树内:
此时情况比较复杂,需要被操作的节点为: 所有节点除去以 $X$ 到 $R$ 的路径上的第一个节点(这个点满足既是 $R$ 的祖先,又是 $X$ 的儿子)为根的子树。那么我们可以根据容斥原理,先对整棵树进行操作,再对那个子树进行相反的操作(如果是查询则减去贡献,如果是修改则减去)。
那么怎么求这个点呢?我们记 $deep_i$ 表示 $i$ 在原图中的深度,让 $R$ 往上移动 $deep_R-deep_X-1$ 个点即可,这个过程显然可以用倍增实现。
如何求 LCA
其实也是之前的分类讨论的套路啦!QAQ
设当前整棵树的根节点为 $r$,修改的节点为 $x,y$。在以 $1$ 为根节点的前提下,我们也可以分类讨论!(以下内容参考 $\text{Codeforces}$ 官方题解)
- 如果 $x,y$ 都在 $r$ 的子树内,那么 $\text{LCA}$ 显然为 $\text{LCA}(x,y)$。
- 如果 $x,y$ 只有一个在 $r$ 的子树内,那么 $\text{LCA}$ 肯定为 $r$。
- 如果 $x,y$ 都不在 $r$ 的子树内,我们可以先找到 $p=\text{LCA}(x,r)$,$q=\text{LCA}(y,r)$。如果 $p$ 和 $q$ 不相同,那么我们选择其中较深的一个;如果 $p$ 和 $q$ 相同,那么 $\text{LCA}$ 就是 $p$ 或 $q$。
综上所述,我们可以发现我们要求的 $\text{LCA}$ 就是 $\text{LCA}(x,y)$,$\text{LCA}(x,r)$,$\text{LCA}(y,r)$ 这三者中深度最大的!
时间复杂度:$O(n\log n)$(当然带着巨大常数)
Code
1 |
|