跳转至

树上启发式合并

约 153 个字 66 行代码 预计阅读时间 1 分钟

解决“树上每个节点,询问其子树的信息,离线”,利用重链剖分的思想

dfs维护重儿子

统计答案时,先遍历轻儿子,算完一个儿子就要撤销其贡献(如果需要撤销的话)

再扫重儿子,不撤销重儿子贡献

遍历轻儿子,加入其贡献,即可得到 u 的答案

有关答案的信息通常作为全局变量,所有节点共用

del时不必考虑中间答案的正确性,有关答案的信息可以放在外面重置

vector<int> e[N];
int siz[N],hson[N];
int ans[N];
void dfs0(int u,int fa)
{
    siz[u]=1;
    int mxsz=0;
    for(auto &v:e[u])
    {
        if(v==fa)
            continue;
        dfs0(v,u);
        siz[u]+=siz[v];
        if(siz[v]>mxsz)
        {
            mxsz=siz[v];
            hson[u]=v;
        }
    }
}
void add(int u)
{

}
void del(int u)
{

}
void addsubtree(int u,int fa)
{
    add(u);
    for(auto v:e[u])
    {
        if (v!=fa)
            addsubtree(v,u);
    }
}
void delsubtree(int u,int fa)
{
    del(u);
    for(auto v:e[u])
    {
        if(v!=fa)
            delsubtree(v,u);
    }
}
void dfs(int u,int fa)
{
    for(auto v:e[u])
    {
        if(v==fa || v==hson[u])
            continue;
        dfs(v,u);
        delsubtree(v,u);
        //重置有关答案的信息
    }
    if(hson[u])
        dfs(hson[u],u);
    add(u);
    for(auto v:e[u])
    {
        if(v!=fa && v!=hson[u])
            addsubtree(v,u);
    }
    ans[u] = 114514;
}