耳分解与双极定向
耳分解
耳分解能极好地维护连通性问题。
很形象的说法,设最初的子图为 \(G_0\),原图为 \(G_N\),满足 \(G_0\) 是一个边双连通分量。
每一次加一条“耳”,由图 \(G_i\) 转到图 \(G_{i+1}\)。“耳”就是一条形如 \((x_1 \to x_2 \to x_3...\to x_k)\) 的路径,满足点 \(x_1,x_k \in G_i\),\(\forall_{1<i<k},x_i \notin G_i\)。
我们称 \(x_1 \neq x_k\) 的“耳”为开耳。
结论:
- 边双必然存在耳分解
- 点双必然存在开耳分解
证明只需在 dfs 树上操作即可得证。
例题:P5776(洛谷)
双极定向
一个问题:一张无向图 \(G = (V,E)\),将边定向得到一个 DAG(有向无环图),满足无入度的点只有一个,无出度的点也只有一个。
先考虑有解的条件。
我们先求出圆方树,可以得到:若方点连成一条链则定然有解。
构造我们从拓扑序入手,容易发现对于割点,一定是这个点双中拓扑序最后面的,于是我们以点双中在拓扑序中第一个出现的点为根建出 dfs 树。
然后我们考虑 tarjan 算法,对每个点维护两条边,一条连向父亲 \(f(x)\),一条连向深度最浅的与其有边的点 \(low(x)\)。
于是我们就从下往上考虑,对于每个点 \(x\) 用 vector 维护一个后继列表 \(L_x\),每次删一个叶子 \(u\),就在 \(low(x)\) 和 \(f(x)\) 处加入点 \(u\),最后再 dfs 按顺序递归即可得到一组合法拓扑序。
例题:P9394(洛谷)
点击查看代码
#include<bits/stdc++.h>
#define fir first
#define sec second
#define int long long
#define lowbit(x) x&(-x)
#define mkp(a,b) make_pair(a,b)
using namespace std;
typedef pair<int,int> pir;
inline int read(){
int x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1; c=getchar();}
while(isdigit(c)){x=x*10+(c^48); c=getchar();}
return x*f;
}
const int inf=1e9,N=5e5+5;
int n,m,nd;
vector<int> ed[N],re[N];
int dfn[N],low[N],cnt;
int st[N],top;
inline void tarjan(int x){
st[++top]=x;
dfn[x]=low[x]=++cnt;
for(auto v:ed[x]){
if(!dfn[v]){
tarjan(v);
low[x]=min(low[x],low[v]);
if(dfn[x]==low[v]){
nd++;
re[nd].push_back(x);
re[x].push_back(nd);
for(;st[top+1]!=v;top--){
int p=st[top];
re[nd].push_back(p);
re[p].push_back(nd);
}
}
}
else low[x]=min(low[x],dfn[v]);
}
}
int siz[N],f[N],lf[N],ans;
int S,T;
inline void pre(int x,int fa){
siz[x]=(x<=n);
int mx=0,sec=0;
for(auto v:re[x]){
if(v==fa) continue;
pre(v,x);
siz[x]+=siz[v];
if(siz[mx]<siz[v]) sec=mx,mx=v;
else if(siz[sec]<siz[v]) sec=v;
}
int res=0;
if(x<=n){
res=max(res,n-siz[mx]-siz[sec]);
f[x]=siz[x]-siz[mx];
}
else{
for(auto v:re[x]){
if(v==fa||v==mx||v==sec) continue;
res=max(res,siz[v]);
}
f[x]=max(res,siz[sec]);
res=max(res,n-siz[x]);
}
res=max({res,f[mx],f[sec]});
f[x]=max(f[x],f[mx]);
lf[x]=(mx?lf[mx]:x);
if(res<ans){
ans=res;
if(mx) S=lf[mx];
else S=x;
if(sec) T=lf[sec];
else T=x;
}
}
int Fa[N];
int Dfn[N],sz[N],id[N],tot;
inline void dfs(int x,int fa){
Fa[x]=fa,sz[x]=1;
Dfn[x]=++tot,id[tot]=x;
for(auto v:re[x]){
if(v==fa) continue;
dfs(v,x);
sz[x]+=sz[v];
}
}
int dep[N],ff[N],vis[N],Low[N];
int mxdep;
int vv[N],pt[N];
vector<int> D[N],ad[N];
vector<vector<int> > res;
int P[N];
inline void init(int x,int fa){
ff[x]=fa;
vis[x]=1;
dep[x]=dep[fa]+1;
mxdep=max(mxdep,dep[x]);
for(auto v:ed[x]){
if(v==fa||!vv[v]) continue;
if(vis[v]){
if(dep[v]<dep[x]){
if(!Low[x]||dep[Low[x]]>dep[v]) Low[x]=v;
}
continue;
}
init(v,x);
if(!Low[x]||dep[Low[x]]>dep[Low[v]]) Low[x]=Low[v];
}
D[dep[x]].push_back(x);
}
inline void gtV(int x){
vector<int> seq;
if(!pt[x]){
for(int i=Dfn[x];i<Dfn[x]+sz[x];i++){
if(id[i]<=n)
seq.push_back(id[i]);
}
}
else{
seq.push_back(x);
for(auto v:re[x]){
if(pt[v]) continue;
for(int i=Dfn[v];i<Dfn[v]+sz[v];i++)
if(id[i]<=n) seq.push_back(id[i]);
}
}
res.push_back(seq);
}
inline void dfs2(int x){
gtV(x);
vis[x]=1;
for(auto v:ad[x]) if(!vis[v]) dfs2(v);
ad[x].clear();
}
inline void solve(int now,int st,int ed){
mxdep=0;
for(auto v:re[now]) vv[v]=1,vis[v]=0;
init(st,0);
vector<int> seq;
for(int t=ed;t;t=ff[t]) vis[t]=0,seq.push_back(t);
reverse(seq.begin(),seq.end());
for(int i=mxdep;i>=1;i--){
for(auto x:D[i]){
if(!vis[x]) continue;
vis[x]=0;
if(ff[x]) ad[ff[x]].push_back(x);
if(Low[x]) ad[Low[x]].push_back(x);
}
D[i].clear();
}
for(int t=ed;t;t=ff[t]) vis[t]=1;
for(auto x:seq){
if(x==st){
for(auto v:ad[x]) if(!vis[v]) dfs2(v);
ad[x].clear();
}
else dfs2(x);
}
for(auto v:re[now]) vv[v]=0;
}
signed main(){
nd=n=read(),m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
ed[u].push_back(v);
ed[v].push_back(u);
}
tarjan(1);
ans=n,pre(1,0);
dfs(S,0);
gtV(T);
int lst=0;
for(int now=T;now;now=Fa[now]) pt[now]=1;
for(int now=T;now;now=Fa[now]){
if(now>n) solve(now,lst,Fa[now]);
lst=now;
}
int Mx=0;
cout<<ans<<' '<<res.size()<<'\n';
for(auto tmp:res){
cout<<tmp.size()<<' ';
Mx=max(Mx,(int)tmp.size());
for(auto v:tmp) cout<<v<<' ';
puts("");
}
}
</details>

浙公网安备 33010602011771号