首页 > 其他分享 >支配树

支配树

时间:2024-06-04 21:34:54浏览次数:10  
标签:sdom 支配 有向图 int 100000 idom

支配

在有向图G中,存在源点s,若从s出发的到达点y的路径都经过点x,称x支配y

注意:若源点s有多个,则可以虚拟一个起点

  • 性质1.源点s支配所有的点,点x一定支配x本身
  • 性质2.支配的传递性,若x支配y,y支配z,则x支配z
  • 性质3.若x支配y,y支配x,则有x=y
  • 性质4.若x支配z,y也支配z,则xy之间一定存在支配关系

这几条性质是显然的,就不证明了

支配树

定义dom[i]表示支配点i的点集,定义idom[i](immediate dominator)表示支配点i的点集中离i最近的且不等于i的点

  • 性质5.除了源点s,所有点i都有唯一的idom[i]

根据性质5,将点i指向idom[i]即可得到一棵树,称之为原有向图的支配树

  • 性质6.支配树的根节点为原图的源点s
  • 性质7.支配树上点i的所有祖先节点就是点集dom[i]

根据性质4,点集dom[i]会形成一条支配链,则性质7得证

应用场景

无向图的必经点的分析工具是圆方树,有向图的必经点分析工具是支配树

DAG(有向无环图)的支配树

对于DAG的拓扑序,显然拓扑序大的结点不可达拓扑序小的结点,进而拓扑序大的结点不能支配拓扑序小的结点。

对于点y,其idom[y]=lca(x1,x2,...,xk),其中x1,x2,...,xk表示y的所有入边的点,lca为最近公共祖先

具体实现的时候每个点加入树的时候处理一下倍增信息,总时间复杂度O(nlogn)

例题

P2597 [ZJOI2012] 灾难
板题
注意:题目没有保证只有一个源点

#include<bits/stdc++.h>
using namespace std;
int n;
long long sz[100];
vector<int> v[100000],v1[100000],v2[100000];
int dep[100000],dp[100000][51],siz[100000],si[100000];
int dom[100000];

inline int read(){
	char ch;int x=0;bool f=false;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=true;
	for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
	if(f) x=-x;
	return x;
}

int lca(int a,int b){
	if(dep[b]>dep[a]) swap(a,b);
	int op=(dep[a]-dep[b]);
	for(int i=50;i>=0;i--){
		if(op<sz[i]) continue;
		op-=sz[i];
		a=dp[a][i];
	}
	if(a==b) return a;
	op=dep[a];
	for(int i=50;i>=0;i--){
		if(op<sz[i]) continue;
		if(dp[a][i]==dp[b][i]) continue;
		op-=sz[i];
		a=dp[a][i],b=dp[b][i];
	}
	return dp[a][0];
}

void get_lca(int now){
	if(now==0) return;
	int k=v1[now][0];
	for(int i=1;i<v1[now].size();i++){
		k=lca(k,v1[now][i]);
	}
	dom[now]=k;
	dp[now][0]=k,dep[now]=dep[k]+1;
	int op=dep[now];
	v2[k].push_back(now);
	//cout<<k<<" "<<now<<endl;
	for(int i=1;i<=50;i++){
		if(op<sz[i]) break;
		dp[now][i]=dp[dp[now][i-1]][i-1];
	}
}

void dfs(int now){
	//cout<<"now: "<<now<<endl;
	siz[now]=-1;
	get_lca(now);
	for(int i=0;i<v[now].size();i++){
		int to=v[now][i];
		siz[to]--;
		if(siz[to]==0) dfs(to);
	}
}

void dfss(int now,int fa){
	//cout<<now<<endl;
	for(int i=0;i<v2[now].size();i++){
		if(v2[now][i]==fa) continue;
		dfss(v2[now][i],now);
		si[now]+=si[v2[now][i]];
	}
}

int main(){
	cin>>n;
	sz[0]=1;
	for(int i=1;i<=50;i++){
		sz[i]=sz[i-1]*2;
	}
	int u,op=0;
	for(int i=1;i<=n;i++){
		op=0;
		while(u=read()){
			if(!u) break;
			op++;
			v[u].push_back(i);
			v1[i].push_back(u);
			siz[i]++;
		}
		if(!op){
			v[0].push_back(i);
			v1[i].push_back(0);
			siz[i]++;
		}
	}
	//for(int i=1;i<=n;i++) cout<<siz[i]<<endl;
	dfs(0);
	//cout<<"Yes"<<endl;
	for(int i=0;i<=n;i++) si[i]=1;
	dfss(0,-1);
	for(int i=1;i<=n;i++) cout<<si[i]-1<<"\n";
	return 0;
}

有向图的支配树

对有向图跑DFS树,得到每个点的时间戳dfn[i],并约定点x<y,当且仅当dfn[x]<dfn[y](注意,该约定在下文的半支配点中任然生效)

  • 性质1.若x<y,则原图中xy的所有路径都经过树上xy的公共祖先

半支配点(semi-dominator)

半支配点与有向图支配树算法相关

注意:本节中的祖先为DFS树上的祖先

定义一个点x(x!=s)的半支配点为sdom[x]。满足在原图上,存在一条路径从sdom[x]x,除了xsdom[x]之外的任意一点y(必须存在y),dfn[y]>dfn[x]。且sdom[x]是满足条件的点中dfs序最小的。

  • 性质2.sdom[x]<fa[x]
  • 性质3.对于任意x!=s,sdom[x]xDFS树上的祖先结点
  • 性质4.对于任意x!=s,idom[x]一定是sdom[x]的祖先结点

对于性质4,假设idom[x]不是sdom[x]的祖先结点,那么根节点s一定可以直接走到sdom[x],不经过idom[x]

根据sdom[x]的定义,其可以不经过时间戳比x更小的点到达x, 而idom[x]一定是x的祖先,自然idom[x]<x,所以sdom[x]可以不经过idom[x]走到x,产生矛盾

  • 定理1.对于任意点x!=s,如果点ysdom[x]x路径上的一点且x!=y,且任意y都满足sdom[y]>=sdom[x],那么idom[x]=sdom[x]
  • 定理2.对于任意点x!=s,设y是sdom[x]到x路径上的一点,y!=x,且sdom[y]为这条路径上最小的点,若sdom[y]<=sdom[x],那么idom[x]=idom[y]

寻找有向图idom[x]的方法

对于任意x!=s,设ysdom[x]x路径上的点,y!=x,且sdom[x]为这条路径上最小的点,那么\(idom[x]=\begin{Bmatrix}sdom[x](sdom[y]=sdom[x])\\idom[y](sdom[y]<sdom[x])\end{Bmatrix}\)
于是只需要求出sdom[x]即可

寻找有向图sdom[x]的方法

对于任意点x!=s,设y1x的祖先结点中在原图中存在边指向x的最小点

设点p>x,且p能够通过原图的边到达点x

y2为所有p中最小的sdom[p],那么:

\[sdom[x]=min(y1,y2) \]

全步骤

  • 1.跑一棵生成树,得到DFS
  • 2.求出半支配点sdom[x]
  • 3.利用结论求出一部分点的idom[x]
  • 4.求出剩余点的idom[x]

标签:sdom,支配,有向图,int,100000,idom
From: https://www.cnblogs.com/wangwenhan/p/18231695

相关文章

  • 一般图的支配树
    P5180【模板】支配树来咯,我们来说说一般图上的支配树。(前排提醒:本文实质是对老师讲的内容的补充,阅读本文前应该知道\(\operatorname{idom}\)及其在DAG上的求解方法,具体可以去查看ZJOI2012灾难的题解。)常见的做法是Languaer-Tarjan算法,该算法的核心在于提出了半支配点......
  • USACO 2008 Jan G]Cell Phone Network 最小支配集(最小覆盖集)
    题目描述FarmerJohnhasdecidedtogiveeachofhiscowsacellphoneinhopestoencouragetheirsocialinteraction.This,however,requireshimtosetupcellphonetowersonhisN(1≤N≤10,000)pastures(convenientlynumbered1..N)sotheycanal......
  • 多目标应用:基于非支配排序的蜣螂优化算法(Non-Dominated Sorting Dung beetle optimize
    一、柔性作业车间调度问题柔性作业车间调度问题(FlexibleJobSchedulingProblem,FJSP)的描述如下:n个工件{J,J......
  • P2597 [ZJOI2012] 灾难(DAG上的支配树)
    题目链接所谓支配树,就是将关系转为一棵树,使得将树上点\(x\)单独去掉其祖先的任意一个,\(x\)均不能选择,而非其父亲的点单独去掉对该点无影响。而其字树内的点则为去掉该点一定不能选择的点。对于本题,如何建树?将原图连边(被吃的向捕食者连),拓扑排序,若当前点为\(x\),则其所有儿子都......
  • 支配树
    DominatorTree被支配哩。自闭哩。。。没有详细的证明。Dominator对于一个任意的有向图,我们钦定一个入口\(s\),对于任意一个节点\(u\),如果从\(s\tou\)的任意路径都经过节点\(v\),称为\(v\)支配\(u\),\(v\)也是\(u\)的一个支配点,记作\(v\dom\u\)。容易发现,......
  • GYM102596L Yosupo's Algorithm【分治,支配对】
    给定平面上\(2n\)个点,每个点有坐标\((x_i,y_i)\),权值\(w_i\)及颜色\(c_i\)。所有点满足:若\(c_i=0\),则\(x_i<0\);若\(c_i=1\),则\(x_i>0\)。\(q\)次查询,每次给定\(L_i,R_i\),你需要选择两个点\(i,j\)满足如下条件:\(c_i=0,c_j=1\)。\(x_i<L,x_j>R\)或\(x_......
  • 你有被if-else支配过吗?看完这篇文章,你就知道该怎么做
    在日常工作中,如果让你碰到一大堆if-else嵌套的代码,你会怎么做?背景最近在给之前负责的项目做CR的时候,在项目代码中发现有大量的if-else判断语句,阅读起来非常的折磨人而且也不利于后期的维护扩展,比较容易出问题。当时我直接气血上涌,差点昏过去。缓过几分钟之后,把写这段代码的......
  • 支配树
    支配关系给定一张有向图,钦定一个入口\(s\),对于一个节点\(u\),若从\(s\)到\(u\)的每一条路径都经过某一个节点\(v\),则我们称\(v\)支配\(u\),记作$v,\text{dom},u$,注意对于\(s\)不能到达的结点,其支配关系是无意义的,因此我们默认\(s\)能到达图上的所有节点引......
  • 控制流图+支配树
    编译器优化记录(1)0.为啥要写这个记录我感觉自己平时整理自己想法的机会实在是太少了。即便是对于自己花了很多时间想、或是花了很多时间学的东西,同样如此。写编译器优化的阶段学了很多方法,也看到了很多人类智慧,我希望能从头梳理一下认识它们的过程,来更好地体悟。我身边有几位......
  • 「黑科技」支配树
    定义给定一张有向图与一个起点\(s\),如果要去掉起点\(s\)到某个点\(v\)的中间的某个点\(u\)后无法到达,那么称点\(u\)支配点\(v\),\(u\)是\(v\)的一个支配点最近支配点\((idom[u])\)\(u\)的支配点中距离\(u\)最近的一点支配树由所有边\(idom[u]\rightar......