dsu on tree学习笔记

这几天学习了dsu on tree这个强大的静态离线查询子树问题的技巧

dsu on tree就是树上启发式合并,当我们要处理子树问题的时候,如果暴力做的话,每次对以这个点为根的子树计算答案,复杂度是\(O(n^2)\)

但是我们每次暴力完之后可以保留一棵子树对父亲的贡献,那么我们可以选取该父亲轻重链剖分后的重儿子,这样保证轻儿子组成的边只有\(logn\)级,那么复杂度就降为了\(O(nlogn)\)

放个写dsu on tree的板子吧QAQ

void dfs(int u)
{
    for (int i = head[u];i;i = nxt[i])
    {
        int v = edge[i];
        if (v == son[u])
            continue;
        dfs(v);//处理轻儿子
        clear(v);//清楚轻儿子的贡献
    }
    if (son[u])
        dfs(son[u]);//处理重儿子,不清除贡献
    for (int i = head[u];i;i = nxt[i])
    {
        int v = edge[i];
        if (v == son[u])
            continue;
        modify(v);//轻儿子子树加,可以用dfs序完成
    }
    add(u);//单点加
    vector <Query>::iterator it;
    for (it = d[u].begin();it != d[u].end();it++)
        ans[it -> id] = query(it -> d);//对离线的询问更新答案
}

然后写了几道比较板子的题,难的题以后刷到会放上来

  1. CF600E Lomsat gelral

题意:求树中每个子树的最多的颜色编号的和

解:开个桶记录颜色数,更新最多的和编号和就好了

  1. CF570D Tree Requests

题意:每次查询以a为根的子树内深度为b的节点上的字母重新排列之后是否能构成回文串

解:能成为回文串要么出现个数全为偶数或者有一个是奇数,那么考虑状压记录每个字母的奇偶性,用lowbit(s)==s更新答案

  1. CF208E Blood Cousins

题意:给你一片森林,每次询问一个点与多少个点拥有共同的k级祖先

解:先跳到祖先,然后变为查询一个点往下走k条边能走到点的个数,这个直接开桶数就好了

  1. CF246E Blood Cousins Return

题意:给定一片森林,每次询问一个节点的K-Son共有个多少不同的名字。一个节点的K-Son即为深度是该节点深度加K的节点。

解:和上题基本一致,多开个map记录下重复的就好了

  1. CF1009F Dominant Indices

题意:给定一棵树。设d(u,x)为u子树中到u距离为x的节点数。对于每个点,求一个最小的k,使得d(u,k)最大。

解:和第一题的思路,每个深度记录节点数,然后用维护的答案减去当前节点深度

  1. CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

题意:求每个子树中最长的路径,其中该路径上的字符经过重新排序后可以变成一个回文串

解:类似于第二道题的判断方式,开桶记录所有的状态的最长长度,每次枚举\(2^i\)拼接两个路径更新最长长度,放个代码

  1. uoj284. 快乐游戏鸡

题面有点长,然后这个不完全是dsu on tree,解法看题解

posted @ 2020-07-03 21:38  eee_hoho  阅读(213)  评论(0编辑  收藏  举报