#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
struct Node{int to,next;};//边
int n,m,dfn[N],clo,rev[N],f[N],semi[N],idom[N];// idom[x]是支配树上x的父亲 dfn[x]是x的拓扑序
//n个点m条边,n为起点求支配树
struct Graph{//整个图
Node E[N];int head[N],tot;
inline void clear(){
tot=0;
for(int i=0;i<=n;++i)head[i]=0;
}
inline void link(int u,int v){
E[++tot]=(Node){v,head[u]};head[u]=tot;
}
}pre,nxt,dom;//dom是最后那棵支配树
struct uset{
int fa[N],Mi[N];
inline void init()
{
for(int i=1;i<=n;++i)
fa[i]=Mi[i]=semi[i]=i;
}
inline int find(int x)
{
if(fa[x]==x)return x;
int fx=fa[x],y=find(fa[x]);
if(dfn[semi[Mi[fx]]]<dfn[semi[Mi[x]]])Mi[x]=Mi[fx];
return fa[x]=y;
}
}uset;
inline void tarjan(int x){//求拓扑序
dfn[x]=++clo;rev[clo]=x;
for(int e=nxt.head[x];e;e=nxt.E[e].next)
{
if(!dfn[nxt.E[e].to])
f[nxt.E[e].to]=x,tarjan(nxt.E[e].to);
}
}
inline void calc(){
for(int i=n;i>=2;--i)
{
int y=rev[i],tmp=n;
for(int e=pre.head[y];e;e=pre.E[e].next)
{
int x=pre.E[e].to;if(!dfn[x])continue;
if(dfn[x]<dfn[y])tmp=min(tmp,dfn[x]);
else uset.find(x),tmp=min(tmp,dfn[semi[uset.Mi[x]]]);
}
semi[y]=rev[tmp];uset.fa[y]=f[y];
dom.link(semi[y],y);
y=rev[i-1];
for(int e=dom.head[y];e;e=dom.E[e].next)
{
int x=dom.E[e].to;uset.find(x);
if(semi[uset.Mi[x]]==y)idom[x]=y;
else idom[x]=uset.Mi[x];
}
}
for(int i=2;i<=n;++i){
int x=rev[i];
if(idom[x]!=semi[x])
idom[x]=idom[idom[x]];
}
//建支配树
dom.clear();
for(int i=1;i<n;++i)
dom.link(idom[i],i);
}
void clear(){//清空
pre.clear();nxt.clear();dom.clear();
for(int i=1;i<=n;++i)
dfn[i]=rev[i]=semi[i]=idom[i]=f[i]=0;
n=0;m=0;clo=0;
}
int main(){
while(~scanf("%d%d",&n,&m)){
clear();
for(int i=1;i<=m;i++){//建立正反两个图
int u,v;
scanf("%d%d",&u,&v);
nxt.link(u,v);
pre.link(v,u);
}
tarjan(n);//以n为根
uset.init();
calc();
}
return 0;
}
支配树
最新推荐文章于 2020-08-24 21:01:47 发布