[洛谷P5180]【模板】支配树

  • 对于 D A G DAG DAG,拓扑排序 + + + 倍增 L C A LCA LCA 就可以做了(不会的可以先做 [ZJOI2012] 灾难)
  • 对于一般有向图(假设连通),转成等价的 D A G DAG DAG 后采用上述方法即可

  • 首先构造出一棵 d f s dfs dfs 树,记录每个点的 d f n dfn dfn
  • 显然一条边 ( u , v ) (u,v) (u,v) 如果不在 d f s dfs dfs 树上,那么 d f n [ u ] > d f n [ v ] dfn[u]>dfn[v] dfn[u]>dfn[v]
  • 然后定义 x x x 的半支配点 s [ x ] s[x] s[x]
    ( 1 ) (1) (1).如果存在任意一条路径 ( y , x ) (y,x) (y,x),使得这条路径上每个 x , y x,y x,y 之外的点 z z z 都满足 d f n [ z ] > d f n [ x ] dfn[z]>dfn[x] dfn[z]>dfn[x],那么称 y y y 是合法的
    ( 2 ) (2) (2).在所有合法的 y y y 中找一个 d f n dfn dfn 最小的,就是 s [ x ] s[x] s[x]
  • 将所有 s [ x ] s[x] s[x] x x x 连边,再加上 d f s dfs dfs 树,就组成了一个等价的 D A G DAG DAG

  • 考虑这样为什么是对的
    ( 1 ) (1) (1). s [ x ] s[x] s[x] 一定是 x x x d f s dfs dfs 树上的祖先,因此新图无环
    ( 2 ) (2) (2). s [ x ] s[x] s[x] x x x 一定有至少两条边不相交的路径
    ( 3 ) (3) (3). s [ x ] s[x] s[x] 还是所有合法点在 d f s dfs dfs 树上的祖先,因为 d f n dfn dfn 最小
  • 注意 s [ x ] s[x] s[x] 不一定支配 x x x,如果不存在合法点,那么 s [ x ] s[x] s[x] d f s dfs dfs 树上的父亲
  • 有什么不懂的画个图即可理解

  • 考虑怎么求 s [ x ] s[x] s[x],按 d f n dfn dfn 降序枚举 v v v,然后枚举边 ( u , v ) (u,v) (u,v)
  • 维护并查集,记录 v v v 已经枚举过的祖先中, d f n dfn dfn 最小的那个,记为 m n [ v ] mn[v] mn[v]
  • 每做完一个点 v v v,把 v v v f a [ v ] fa[v] fa[v] 合并
  • 根据 d f n [ u ] dfn[u] dfn[u] d f n [ v ] dfn[v] dfn[v] 大小关系进行讨论
  • 详见代码,还是那句话,有什么不懂的画个图即可理解
// 求半支配点部分
inline int find(int x)
{
    if (x == fa[x]) return x;
    int t = fa[x];
    fa[x] = find(fa[x]);
    if (dfn[s[mn[t]]] < dfn[s[mn[x]]]) mn[x] = mn[t];
    return fa[x];
}

inline void init()
{
    int i, j;
    for (i = 1; i <= n; i++) fa[i] = mn[i] = s[i] = i;
    for (i = id[0]; i >= 2; i--)
    {
        int v = id[i], len = h[v].size(), res = n;
        // res 为最小合法点的 dfn,id[res] 即 dfn 为 res 的点,即 s[x]
        for (j = 0; j < len; j++)
        {
            int u = h[v][j];
            if (!dfn[u]) continue; // 注意可能图不连通
            if (dfn[u] < dfn[v]) res = min(res, dfn[u]);
            else
            {
                find(u);
                res = min(res, dfn[s[mn[u]]]);
                // 用 u 的已做过的祖先的最小 dfn 更新 res
            }
        }
        s[v] = id[res];
        add(s[v], v);
        fa[v] = anc[v]; // anc[v] 为 v 的祖先,fa[v] 是并查集,带路径压缩
    }
}
  • 由于拓扑排序 + + + 倍增 L C A LCA LCA,时间复杂度 O ( n log ⁡ n + m ) O(n\log n + m) O(nlogn+m)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值