初涉DSU on tree
Posted antiquality
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初涉DSU on tree相关的知识,希望对你有一定的参考价值。
早先以为莫队是个顶有用的东西,不过好像树上莫队(不带修)被dsu碾压?
dsu one tree起源
dsu on tree是有人在cf上blog上首发的一种基于轻重链剖分的算法,然后好像由因为这个人后来在cf上办了场比赛出了道dsu on tree的裸题由此出名?
这个是原博客地址:http://codeforces.com/blog/entry/44351
大概思想就是一种树上启发式合并,利用轻重链剖分把重复计算的答案利用起来,从而把时间复杂度控制在$O(n log n)$(不过不能修改)。
注意dsu的一大特点:一次dsu之后是把整棵树的答案都处理出来,因此它更适合大量查询的情况。
下面讲一下算法流程:
1.预处理树的结构,把$fa$,$son$,$tot$处理出来。具体操作参见树剖。
2.为了统计当前节点答案,先递归处理所有轻儿子。然后递归回当前节点时,其子树内除了重儿子都已经处理好答案了。
3.如果有重儿子,那么递归重儿子同时标记重儿子这个节点
4.现在子树信息都已经处理好了,考虑向上合并信息。我们把子树内所有点都统计颜色一遍(除了重儿子的家族)
5.现在子树信息传递好了
6.如果这个节点是轻儿子转移过来的,那么清除这颗子树所有信息(包括子树里的重儿子)
1 void color(int x, int c) //把x的子树都统计一遍 2 { 3 cnt[a[x].col] += c; 4 if (c>0&&mx <= cnt[a[x].col]) 5 { 6 if (mx < cnt[a[x].col]) mx = cnt[a[x].col], sum = 0; 7 sum += a[x].col; //如果现在是 8 } 9 for (int i=0; i<f[x].size(); i++) 10 if (f[x][i]!=a[x].fa&&!vis[f[x][i]]) //处理儿子节点 11 color(f[x][i], c); 12 } 13 void dfs2(int x, bool fl) //dsu:x表示当前节点 fl表示当前节点是轻儿子还是重儿子 14 { 15 for (int i=0; i<f[x].size(); i++) 16 if (f[x][i]!=a[x].son&&f[x][i]!=a[x].fa) 17 dfs2(f[x][i], 0); 18 if (a[x].son!=-1) dfs2(a[x].son, 1), vis[a[x].son] = 1; 19 color(x, 1); //c==1是统计答案;c==0是消除答案 20 ans[x] = sum; 21 if (a[x].son!=-1) vis[a[x].son] = 0; 22 if (!fl) color(x, -1), mx = sum = 0; 23 }
就这些
题目
以上是关于初涉DSU on tree的主要内容,如果未能解决你的问题,请参考以下文章