圆方树学习笔记

前言#

模拟赛要求图上距离为 k 的节点对数,就学了一下圆方树
众所周知,树有很多美妙的性质,但是有些题目非把树上问题搬到图上,这时我们就要上圆方树了。
那么圆方树是什么呢?(是圆形节点和方形节点构成的树)
圆方树(Block forestRoundsquare tree)1就是一种将图变成树的方法。本文将介绍圆方树的构建,性质和一些应用。

定义#

圆方树一开始是为“仙人掌”定制的。(每条边在不超过一个简单环中的无向图)
但是现在发现我们也可以在一般图中使用它。

前置知识:点双联通分量。#

割点的定义:在一个图中,如果把一个节点 i 删除后,原图不再联通,那么我们称这个点是割点
点双联通分量的定义:当一个图中没有割点,当前图是点双联通分量
我们用 Tarjan 求出点双联通分量,在此不在累述。

而一个图的 点双连通分量 则是一个 极大点双连通子图
性质:与强连通分量等不同,一个点可能属于多个点双,但是一条边属于恰好一个点双
那么在圆方树中,每一个原来的节点我们用圆形的点表示,每一个点双用方点表示。
给大家放几个图感受一下:

imageimageimage
(图片来自 oi-wiki.org)

圆方树的节点个数小于等于原来节点的两倍,原因很简单,因为原图的点割点的个数最坏情况下也最多有 N 个,所以做题时注意数组要开两倍大小。

构建圆方树#

因为原图中有多少个联通分量就有多少个圆方树,所以我们设原图就是连通图
因为圆方树的构建和点双联通分量有关,所以我们直接调用 Tarjan 搞出割点就可以啦。

根据 Tarjan 算法:
每一个 low[i] 表示当前 i 节点最多一次返祖边或向父亲的树边 能访问到的点的最小 DFS 序。
稍微构建一个图模拟一下就可以发现,对于每一个点双联通分量,都是原图中对应的一个环,且每一条树边恰好被分在一个点双中,对于一个点双中最靠上的节点,满足 dfni=lowi 的性质。
记录一个栈,存储还未确定所属点双(可能有多个)的节点。(和 Tarjan 一样)
对于每一个从栈弹出的节点,我们让它和新建的节点相连接。记得最后要和 u 相连。
如图所示:(无加粗的是新加入的方形节点)

Code#

// addline 为圆方树的边
// head2, to2.... 为原图的边
inline void tarjan(int now) {
  dfn[now] = low[now] = ++dfnnum;
  sta[++top] = now;
  for (int i = head2[now]; i; i = then2[i]) {
    int t = to2[i];
    if (!dfn[t]) {
      tarjan(t);
      low[now] = std::min(low[now], low[t]);
      if (low[t] == dfn[now]) {
        ++cnt;
        while (top && sta[top] != t) {
          addline(cnt, sta[top]);
          addline(sta[top], cnt);
          top--;
        }
        addline(cnt, sta[top]);
        addline(sta[top], cnt);
        top--;
        addline(now, cnt);
        addline(cnt, now);
      }
    } else
      low[now] = std::min(low[now], dfn[t]);
  }
}

例题#

P4630 [APIO2018] Duathlon 铁人两项
CF487E Tourists

作者:Aonynation

出处:https://www.cnblogs.com/Oier-GGG/p/16049166.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Aonynation  阅读(242)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示