树上问题总结
前言
暑假里通过托老师的分享,系统的学习了树上的一些操作,发现其中有很多有用的trick,所以总结一下。
托神无敌!
一
-
问题形式:批量处理f(dep(lca(x,y)))的问题,f(x)是一个关于x的函数
-
过程:先树剖,然后将x到根的路径先处理出贡献,(对于不同深度带来不同值,可以在数据结构里体现),然后在对于每一个y,统计其到根的路径上的贡献之和。
-
原理:x与y的lca正是x到根的路径与y到根的路径的第一个交点,其深度自然是两条路径的重合的长度。
-
例题:
有 $m $次询问,每次询问给出 \(l\ r\ z\),求 \(\sum_{i=l}^r dep[LCA(i,z)]\) 。
——[LNOI2014]LCA
二
-
问题:处理关于树上直径的问题
-
关键:
- 任意一个点的最远距离的点一定是直径的某一端点(必须是树才可以)
- 任何一个树的直径中心只会有一个或两个。
-
例题:
q次询问,每次求出若干个点的最小联通块的所有可能的直径中心
——2021.8.26 test T2
三
-
问题:一个路径的权值等于路径上任意点对的权值和,求所有路径的权值和。
-
关键:对于每个点对计算其贡献次数。
- 若点对\((x,y)\)没有祖先关系,次数为\(size[x]\times size[y]\)
- 若点对\((x,y)\)有祖先关系,设x是y的祖先,次数为\((n-size[x]+1)\times size[y]\)
-
原理,计算包含这两个点对的路径的条数。
-
例题:
树上每个节点代表了字典树上的一个节点,记为\(S(x)\),一条路径\(K\)的权值为
\[f(K)=\sum_{x\in K,y\in K,x<y}f(LCP(S(x),S(y))) \]求树上所有路径的权值和
——Luogu P5439永恒
四
-
问题:处理不同位置关系的点对
-
过程:
-
所有不具有祖先关系的点对
void sous(int x,int fa){ query(); 遍历子树; insert(); }
-
所有具有祖先关系的点对
void sous(int x,int fa){ query(); insert() 遍历子树; delete(); }
-
-
例题
判断一颗树是否满足\(\forall 1 \le i < j \le n,\gcd(a_i, a_j) = a_{\operatorname{lca}(i, j)}\)
——Luogu P7854 GCD Tree
五
-
问题:在不重复的情况下,计算多个点到根路径上的点权和。
-
过程:对点按dfs排序,先计算每个点其路径上的点权和,而重复的部分就是每对相邻的点的lca到根的路径上的点权和,减去即可。
-
原理:类似建虚树的时候将点按dfs排序一样,在有序的情况下,某个点到根路径与现有的路径重合的部分一定是与dfs次小于他的点的lca到根的路径。
-
例题:
利用AC自动机求模式串包含多少模板串。(出现多次算一次)
——[SCOI2012]喵星球上的点名
六
-
问题:每个点产生的贡献需要单独计算,多次询问求根到x的路径的贡献之和。
-
过程:先把问题离线到各个节点上,最后遍历一次树,进入节点加上贡献,退出时减掉。可以看成一些具有祖先关系的点对
-
注意:也可以将不经过根节点的链通过差分变成此类问题。由此也可以扩展成一条路径。
-
例题:
给一颗树,树上的边有一个字符,\(q\) 次询问:每次给两点 \(x,y\) 和一个字符串 \(str\),询问串 \(str\) 在从点 \(x\) 到点 \(y\) 的路径中每条边上的小写字母顺次连接形成的字符串中出现多少次。
——2021.7.20 test T2
七
-
问题:树上DP,父亲的DP值和儿子DP值相关。需要对每个节点单独钦定一次DP值,求根节点的DP值。
-
过程:把DP的转移看成矩阵。遍历一遍树,利用矩阵的结合律,用栈维护根到父亲的转移的矩阵积。对每个节点构建出钦定DP值后的矩阵,乘上栈顶的矩阵,这样就可以快速求出该节点DP固定,其他点不变时根节点的DP值。
-
例题
有一课树。要把树上的节点加入一个集合S,每个点加入集合的概率为。
\[p(u)= \begin{cases} 0&\forall v\in u.son\&u\in S\\ b[u]&other \end{cases} \]每个加入集合的点u会产生贡献,具体为
\[\sum_{u\in S}c[v]\sum_{v\in S\&v\in subtree(u)}s[v] \],你要确定01序列S的值,使上面的式子的期望最大。
——2021.9.13 T3
八
-
问题:在树上确定两个关键点,每个点的贡献是距离小的关键点的距离×权值
-
关键:把每个点到距离最小关键点的路径标记,可以确定有一条边一定不会被标记。因此可以对树划分为两个部分,然后对两颗子树分别考虑贡献。
-
例题:
一颗树,在树上确定两个关键点,每个点的贡献是距离小的关键点的距离×该点权值,最小化贡献之和(\(n\le 10^3\))
——2021.9.16 T4
九
-
问题:每个点有颜色,多次询问求某个点的子树内颜色数。
-
关键:对每种颜色考虑两个dfs序相邻的点,记为\(x,y\),发现\(x,y\)对\(x,y,lca_{x,y}\)分别产生\(1,1,-1\)的贡献。
-
例题
一个每个点有颜色的树, 多组询问,每次询问给出 \(u, d\),求 \(u\) 的子树内深度不超过 \(dep_{u} + d\) 的点集中的颜色种类数,强制在线。
——BZOJ4771 七彩树
十
-
问题:对于树上的一个点 \(x\in[1,n]\) ,需要对每一个点\(i\in[1,n]\)去考虑是否满足一个条件\(p(x,i)\),且只要\(p(x,i)=1\),那么对于\(j\in i\)的子树,都有\(p(x,j)=1\)。定义\(val_x=\sum_{i}[ p(x,i)=1\land p(x,fa_i)=0]\),对每一个 \(x\) 求\(val_x\)
-
关键:想办法去除只有父亲为 \(0\) 自己为 \(1\) 的贡献模式(因为这种方式只能暴力扫整树),我们考虑一颗树,有\(\sum\limits_{i=1}^m d_{a_i}=2m-1\),\(d_i\)为\(i\)的度数大小,\(a_i\)表示这子树中的点。所以\(1=\sum\limits_{i=1}^m(2-d_{a_i})\),那么我们只要给每个点的贡献设为\(2(2-d_i)\),那么\(val_x=\sum_{i=1}^n[p(x,i)=1]\times(2-d_i)\),这样就消去了父亲必须为 \(0\) 的限制。
-
例题
有一棵树,树上的每个叶子都是出入口。开始时,每个出入口都可以放一个农民(也可以不放)。每个时刻,贝茜和农民都可以移动到相邻的一个结点。如果某一时刻农民与贝茜相遇了(在边上或点上均算),则贝茜将被抓住。抓捕过程中,农民们与贝茜均知道对方在哪个结点。
请问:对于结点 \(i\,(1\le i\le N)\) ,如果开始时贝茜在该结点,最少有多少农民,她才会被抓住。
——P4183 [USACO18JAN]Cow at Large P