支配树模板及邻接链表封装

大家都很强, 可与之共勉 。

填一个坑,不然写了都不记得去哪儿找。

一个支配树的板子,看你们都用vector没有O2应该会被卡常数。
所以研究了一下邻接链表封装。
支配树的dom一定要开两倍,因为建树的时候也要加边23333

# define N 50010
# define M 100010

struct edge  {
    int to ;  edge* nxt ;
} ;

struct Graph  {
    edge g [M << 1] ;
    edge *head [N] ;
    Graph ( )  {    memset ( head, 0, sizeof head ) ;   }
    inline void add_edge ( int u, int v )  {
        static edge* NewEdge ( g ) ;
        *( ++ NewEdge ) = ( edge ) {  v, head [u]  } ; head [u] = NewEdge ;
    }
    inline edge*& operator [] ( const int u )  {  return head [u] ;  }
} ;

namespace pbds  {

    inline bool cmp ( const int&, const int& ) ;

    struct DominatorTree  {
        Graph cur, rev ;
        int ufs [N], val [N] ; // Union-Find-Set
        int fa [N], dfn [N], id [N], idx ;  // father on Dfs Tree, Dfs order, Dfs id ;
        int sdom [N], idom [N] ;  // half Dominate point, nearest  Dominate point
        Graph dom ;  // save v that sdom [v] is u, at last it is Dominate Tree ;

        inline void add_edge ( int u, int v )  {
            cur.add_edge ( u, v ), rev.add_edge ( v, u ) ;
        }

        inline void dfs ( int u )  {
            id [dfn [u] = ++ idx] = u ;
            for ( edge* it = cur [u] ; it ; it = it -> nxt )  {
                if ( ! dfn [it -> to] )  {
                    fa [it -> to] = u ;
                    dfs ( it -> to ) ;
                }
            }
        }

        inline int findfa ( int x )  {
            if ( x == ufs [x] ) return x ;
            int y = findfa ( ufs [x] ) ;
            if ( cmp ( sdom [val [ufs [x]]], sdom [val [x]] ) ) val [x] = val [ufs [x]] ;
            return ufs [x] = y ;
        }

        inline void build ( const int s, const int n )  {
            for ( register int i = 1 ; i <= n ; ++ i )  ufs [i] = val [i] = sdom [i] = i ;
            dfs ( s ) ;
            for ( register int i = idx, u ; u = id [i], i > 1 ; -- i )  {
                for ( edge* it = rev [u] ; it ; it = it -> nxt )
                    if ( dfn [it -> to] )  {
                        findfa ( it -> to ) ;
                        sdom [u] = std :: min ( sdom [u], sdom [val [it -> to]], cmp ) ;
                    }
                dom.add_edge ( sdom [u], u ) ;
                register int x = ( ufs [u] = fa [u] ) ;
                for ( edge* it = dom [x] ; it ; it = it -> nxt )  {
                    findfa ( it -> to ) ;
                    idom [it -> to] = cmp ( sdom [val [it -> to]], fa [u]) ? val [it -> to] : fa [u] ;
                }
                dom [x] = 0 ;
            }

            for ( register int i = 2, u ; u = id [i], i <= idx ; ++ i )  {
                ( idom [u] ^ sdom [u] ) ? idom [u] = idom [idom [u]] : 0 ;
                dom.add_edge ( idom [u], u ) ;
            }
        }
    } T ;

    inline bool cmp ( const int& u, const int& v )  { return T.dfn [u] < T.dfn [v] ;  }

}

# undef N
# undef M
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值