非常牛 dsu on tree

轩辕 4721 年,彩笔@硒六爱吃硫,在某日的西艾斯批%你赛中花了两个小时切掉了 T1 和 T2。

随后看到 T3,心想:“这不是傻逼题吗,建下氪卤丝卡珥重构树然后瞎几把低批不就做完了吗。”

发现并不会低批。

思考了一个小时发现并不是沙比低批,而是地艾斯优盎吹。

@硒六爱吃硫 打完暴力。注意到还有 \(40\) min。

what should he/she do?

遗憾的,@硒六爱吃硫 早就忘了地艾斯优盎吹怎么写。最终只拿下 36pts 的高分。

int val[400005], c[400005], b[400005], k;
int siz[400005], son[400005], st[400005], ed[400005], dfn = 0, mp[400005];
int n, m, d;
void dfs1(int x, int fa) {
    siz[x] = 1; mp[st[x] = ++dfn] = x;
    for(int i = head[x]; i; i = e[i].nxt) if(e[i].to != fa) dfs1(e[i].to, x), siz[x] += siz[siz[son[x]] < siz[e[i].to] ? son[x] = e[i].to : e[i].to];
    ed[x] = dfn;
}
void dfs2(int x, int fa, int flg) {
    // flg == 0 表示计算以 x 为根的子树的答案,并不保留答案
    // flg == 1 表示计算以 x 为根的子树的答案,保留答案
    for(int i = head[x]; i; i = e[i].nxt) if(e[i].to != fa && e[i].to != son[x]) dfs2(e[i].to, x, 0);
    if(son[x]) dfs2(son[x], x, 1);
    if(x <= n) //把当前点加入数据结构等;
    for(int i = head[x]; i; i = e[i].nxt) {
        int y = e[i].to;
        if(y == son[x] || y == fa) continue;
        for(int j = st[y]; j <= ed[y]; j++) {
            //计算答案
        }
        for(int j = st[y]; j <= ed[y]; j++) if(mp[j] <= n) //维护数据结构等;
    }
    if(flg == 0) for(int j = st[x]; j <= ed[x]; j++) if(mp[j] <= n) //撤销操作;
}

合并子树的时候拥有一个子树的信息。所以可以处理绝大部分的链合并和子树合并问题。

应该是非常通用的板子。

posted @ 2024-10-22 16:28  QAQfj5  阅读(29)  评论(0编辑  收藏  举报