生活随笔
收集整理的这篇文章主要介绍了
【Cf Edu #47 F】Dominant Indices(长链剖分)
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
要求每个点子树中节点最多的层数,一个通常的思路是树上启发式合并,对于每一个点,保留它的重儿子的贡献,暴力扫轻儿子将他们的贡献合并到重儿子里来。
参考重链剖分,由于一个点向上最多只有$log$条轻边,故每个点最多被合并$log$次。但这不是这题想说的。
由于我们只保留以深度为下标的信息,重链剖分就会多算,以此引出长链剖分,权且作为一个模板来学习。
长链剖分时,每个点以最深的儿子作为长儿子,其余为短儿子。
每个点$O(1)$继承长儿子的信息,将短儿子的信息合并上来。每个点只有作为短儿子时才保留以它为链头的一条长链上的信息,空间复杂度为$O(链长)$。
显然,每次短儿子被合并之后就不会再被访问到了,因为它合并到了一条比它更长的链,而所有的长链都不相交,每条链都以$O(链长)$被合并掉,故总复杂度是$O(n)$的。
这道题只要维护深度为$i$的节点的数量,取最大值即可。
$\bigodot$技巧&套路:
- 以深度为下标的信息,可以考虑长链剖分。
- 通常信息的合并,DSU on tree就可以了。
1 #include <cstdio>
2 #include <vector>
3
4 const int N =
1000005;
5
6 int n, hig[N], res[N], son[N], dep[N];
7 std::vector<
int>
g[N];
8
9 int yun, las[N], to[N <<
1], pre[N <<
1];
10 inline
void Add(
int a,
int b) {
11 to[++yun] = b; pre[yun] = las[a]; las[a] =
yun;
12 }
13
14 void Dfs(
int x,
int Fa) {
15 for (
int i = las[x]; i; i = pre[i])
if (to[i] !=
Fa) {
16 Dfs(to[i], x);
17 if (hig[x] < hig[to[i]] +
1) {
18 hig[x] = hig[to[i]] +
1;
19 son[x] =
to[i];
20 }
21 }
22 if (!
son[x]) {
23 g[x].push_back(
1);
return;
24 }
25 std::swap(g[x], g[son[x]]);
26 res[x] =
res[son[x]];
27 for (
int i = las[x]; i; i = pre[i])
if (to[i] !=
Fa) {
28 if (son[x] !=
to[i]) {
29 int nx = (
int)g[x].size(), nt = (
int)g[to[i]].size();
30 for (
int j =
0; j < nt; ++
j) {
31 g[x][nx - nt + j] +=
g[to[i]][j];
32 if (g[x][nx - nt + j] >= g[x][res[x]]) res[x] = nx - nt +
j;
33 }
34 }
35 }
36 g[x].push_back(
1);
37 if (g[x][res[x]] ==
1) res[x] = (
int)g[x].size() -
1;
38 }
39
40 int main() {
41 scanf(
"%d", &
n);
42 for (
int i =
1, x, y; i < n; ++
i) {
43 scanf(
"%d%d", &x, &
y);
44 Add(x, y); Add(y, x);
45 }
46 Dfs(
1,
0);
47 for (
int i =
1; i <= n; ++
i) {
48 printf(
"%d\n", hig[i] -
res[i]);
49 }
50
51 return 0;
52 }
View Code
转载于:https://www.cnblogs.com/Dance-Of-Faith/p/9322458.html
总结
以上是生活随笔为你收集整理的【Cf Edu #47 F】Dominant Indices(长链剖分)的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。