码迷,mamicode.com
首页 > 其他好文 > 详细

支配树

时间:2020-05-29 20:58:16      阅读:55      评论:0      收藏:0      [点我收藏+]

标签:lin   cpp   ==   vector   span   默认   turn   +=   --   

支配树

(一下的节点大小比较默认为dfs序的大小)

idom支配点——s->t的必经点

sdom半支配点

半支配点

\(sdom[w]\)为能到达w点的v的最小值,要求路径上处理起点终点外所有点大于w

技术图片

性质:

  1. 半支配点唯一
  2. 半支配点一定是dfs树上的祖先
  3. 任意点w(w不等于起点s)的支配点是该节点半支配点的祖先
  4. 存在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);
}

支配树

标签:lin   cpp   ==   vector   span   默认   turn   +=   --   

原文地址:https://www.cnblogs.com/aurora2004/p/12989423.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!