zoukankan      html  css  js  c++  java
  • 支配树

    支配树

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

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

    sdom半支配点

    半支配点

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

    image-20200529150741029

    性质:

    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);
    }
    
  • 相关阅读:
    整理—类型转换
    HTML简历
    数组
    选择语句2
    类型转换、运算符'
    C#(VS)基础
    hdu_1037(水题水疯了。。。史上最水)
    hdu_1033(我怎么找到的这么水的题,只为保存代码。。。)
    hdu_1030(数学题+找规律)
    hdu_1029_hash/map
  • 原文地址:https://www.cnblogs.com/aurora2004/p/12989423.html
Copyright © 2011-2022 走看看