zoukankan      html  css  js  c++  java
  • 支配树学习笔记

    支配树是一种将有向图转化为一棵树的十分有效的方法。

    在这棵树中,每个点的父亲就是一个离它最近的点使得去掉这个点之后,一号点和这个点就会不连通。

    如果这张图是一个普通的(DAG),那么求解支配树的方法比较简单,直接按照拓扑序去做,对于一个点,它在支配树上的父亲就是所有能够到达它的点在树上的(LCA),直接求即可。

    但是现在这张图变成了一张一般的有向图。

    有向图上的支配树是用Lengauer-Tarjan 算法来完成的。

    在这个算法中,引入了半支配点。

    半支配点就是对于一个点,存在一条从半支配点到当前点的路径使得中间经过的所有点的dfs序都大于(u)点。

    求法的话就是按照(dfs)序倒序枚举,对每个点我们用带权并查集求出所有(dfs)序比他大的点的父亲的(min)就是半支配点了。

    可以发现半支配点也会构成一个树形的关系,那么我们求支配点的时候把半支配点到当前点的链拿出来,查找一下这条链上所有点的半支配的最浅点是否是半支配点,需要处理一些情况。

    #include<bits/stdc++.h>
    #define N 200009
    using namespace std;
    typedef long long ll;
    vector<int>vec[3][N];
    int dfn[N],rec[N],f[N],mn[N],sdom[N];
    int idom[N],fa[N],cnt[N];
    int n,m;
    inline ll rd(){
    	ll x=0;char c=getchar();bool f=0;
    	while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f?-x:x;
    }
    void dfs(int u){
    	dfn[u]=++dfn[0];
    	rec[dfn[0]]=u;
    	for(auto v:vec[0][u])
    	    if(!dfn[v]){
    	    	fa[v]=u;dfs(v);
    	    }
    }
    int find(int u){
      if (u==f[u]) return u;
      int rt=find(f[u]);
      if (dfn[sdom[mn[f[u]]]]<dfn[sdom[mn[u]]]) mn[u]=mn[f[u]];
      return f[u]=rt;
    }
    inline void solve(){
    	n=rd();m=rd();
    	int u,v;
    	for(int i=1;i<=m;++i){
    		u=rd();v=rd();
    		vec[0][u].push_back(v);
    		vec[1][v].push_back(u);
    	}
    	dfs(1);
    	for(int i=1;i<=n;++i)mn[i]=f[i]=sdom[i]=i;
    	for(int i=dfn[0];i>=2;--i){
    		int u=rec[i];
    		for(auto v:vec[1][u]){
    			if(!dfn[v])continue;
    			find(v);
    			if(dfn[sdom[mn[v]]]<dfn[sdom[u]])sdom[u]=sdom[mn[v]];
    		}
    		f[u]=fa[u];
    		vec[2][sdom[u]].push_back(u);
    		u=fa[u];
    		for(auto v:vec[2][u]){
    			find(v);
    			idom[v]=u==sdom[mn[v]]?u:mn[v];
    		}
    		vec[2][u].clear();
    	} 
      for (int i=2;i<=dfn[0];++i){
        int u=rec[i];
        if (idom[u]^sdom[u]) idom[u]=idom[idom[u]];
      }
      for(int i=dfn[0];i>1;--i){
      	cnt[idom[rec[i]]]+=++cnt[rec[i]];
      }
      ++cnt[1];
      for(int i=1;i<=n;++i)printf("%d ",cnt[i]);
    }
    int main(){
    	solve();
    	return 0;
    }
    
  • 相关阅读:
    jQuery诞生记-原理与机制
    你所不知的 CSS ::before 和 ::after 伪元素用法
    http中get与post的区别
    Http请求方法
    TCP/IP详解学习笔记(4)-ICMP协议,ping和Traceroute
    TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议
    TCP/IP详解学习笔记(2)-数据链路层
    TCP/IP详解学习笔记(1)-基本概念
    全面解析Java的垃圾回收机制
    深入Java虚拟机:JVM中的Stack和Heap
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/15195752.html
Copyright © 2011-2022 走看看