支配树
Posted aurora2004
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了支配树相关的知识,希望对你有一定的参考价值。
支配树
(一下的节点大小比较默认为dfs序的大小)
idom支配点——s->t的必经点
sdom半支配点
半支配点
(sdom[w])为能到达w点的v的最小值,要求路径上处理起点终点外所有点大于w
性质:
- 半支配点唯一
- 半支配点一定是dfs树上的祖先
- 任意点w(w不等于起点s)的支配点是该节点半支配点的祖先
- 存在v是w的祖先,那么idom[w]不为v的后代就为idom[v]的祖先
求取方法
(v,u)∈E
if(dfn[u]>dfn[v])sdom[u]=min{v};
else sdom[u]=min{sdom[k]};//k为v的祖先,dfn[k]>dfn[u]
最近支配点
存在v支配w,且w的其他支配点均支配v,那么称v为w的最近支配点,记(idom[w]=v)
求解方法
集合P={x到sdom[x]路径上的点集(不包含sdom[x])}
元素(k)为P中sdom的dfn最小的点
if(sdom[k]==sdom[x])idom[x]=sdom[x];
else idom[x]=idom[k];
【模板】支配树
//starusc
/*
数据不清空,爆零两行泪。
多测不读完,爆零两行泪。
边界不特判,爆零两行泪。
贪心不证明,爆零两行泪。
D P 顺序错,爆零两行泪。
大小少等号,爆零两行泪。
变量不统一,爆零两行泪。
越界不判断,爆零两行泪。
调试不注释,爆零两行泪。
溢出不 l l,爆零两行泪。
*/
#include<bits/stdc++.h>
using namespace std;
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<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=2e5+4;
int n,m,tim,dfn[N],idx[N],fa[N],sdom[N],idom[N],ans[N];
vector<int>e1[N],e2[N],e_s[N],e_i[N];
void dfs_1(int x){
dfn[x]=++tim;idx[tim]=x;
for(auto v:e1[x])
if(!dfn[v]){fa[v]=x;dfs_1(v);}
}
namespace dsu{
int fa[N],mn[N];
int find(int x){
if(x==fa[x])return x;
int ret=find(fa[x]);
if(dfn[sdom[mn[fa[x]]]]<dfn[sdom[mn[x]]])
mn[x]=mn[fa[x]];//sdom最小的节点
return fa[x]=ret;
}
}
void tarjan(){
for(int i=n,x;i>1;i--){
x=idx[i];
for(auto v:e2[x]){
dsu::find(v);
if(dfn[sdom[dsu::mn[v]]]<dfn[sdom[x]])
sdom[x]=sdom[dsu::mn[v]];
//(v,u)in E
//if(dfn[v]<dfn[u])sdom[u]=min{v};
//else sdom[u]=min{sdom[k]};//k是v的祖先,dfn[k]?dfn[u]
}
e_s[sdom[x]].push_back(x);
dsu::fa[x]=fa[x];
x=idx[i-1];
for(auto v:e_s[x]){
dsu::find(v);
if(sdom[dsu::mn[v]]==x)idom[v]=x;
else idom[v]=dsu::mn[v];
}
}
for(int i=2;i<=n;i++)//idom要从小到大更新
if(idom[idx[i]]!=sdom[idx[i]])
idom[idx[i]]=idom[idom[idx[i]]];
for(int i=2;i<=n;i++)e_i[idom[i]].push_back(i);
}
void dfs_ans(int x){
ans[x]=1;
for(auto v:e_i[x]){
dfs_ans(v);
ans[x]+=ans[v];
}
}
int main(){
n=read();m=read();
for(int i=1,u,v;i<=m;i++){
u=read();v=read();
e1[u].push_back(v);e2[v].push_back(u);
}
for(int i=1;i<=n;i++)sdom[i]=dsu::fa[i]=dsu::mn[i]=i;
dfs_1(1);
tarjan();
dfs_ans(1);
for(int i=1;i<=n;i++)cout<<ans[i]<<" ";
return (0-0);
}
以上是关于支配树的主要内容,如果未能解决你的问题,请参考以下文章