算法 {树Tree}

算法 {树Tree}

@LOC: 2

树Tree

定义

#無向树#
无向图 G = ( V , E ) G=(V,E) G=(V,E) 满足{1:[任意两点均可达]; 2:[ ∣ V ∣ = ∣ E ∣ + 1 |V| = |E| + 1 V=E+1]};
等價表述: 不存在的(割邊(橋))的連通無向圖 為樹;

@DELI;

#有向树#
對於無向樹G 選擇一個根節點R, 對於G中的任意無向邊a-b 如果a的深度 < b的深度 則講該無向邊變成a->b有向邊;

@DELI;

#子樹#
樹G中, 一個點集S 如果滿足: 對任意a,b \in S, 樹G上a,b的簡單路徑上的所有點 都在S內, 則S對應導出子圖 稱之為子樹;
. 比如對於一顆標準二叉樹(x的子節點為2*x, 2*x+1), 點集{9,4,2,5,1,3}為子樹;

#以x為根的子樹#
樹G中, 由{x, x的所有子節點}組成的點集 對應的導出子圖, 稱之為以x為根的子樹;

#树上(简单)路径#
跟简单路径的定义一样, 不经过重复点的路径;

性质

@MARK: @LOC_1;
#树的所有节点的度数的方案 是全排列#
对于一颗N个点的树, 因为他有N-1条边 因此这N个点的度数之和 一定等于(N-1)*2; 我们令Di数组 表示每个点的度数, 那么一定能够满足: Di >= 1Di之和 == (N-1)*2 (因为树有N-1条边 每个边贡献两个度数);
那么其实 这个结论 不仅是充分性 也是必要性, 换句话说: 满足Di>=1 && Di之和=(N-1)*2Di数组 他一定可以形成一颗N个点的树;
. 举个例子, N=4, 对于0-1-2-3这个树 他的度数为[1,2,2,1] 满足结论; 那么反过来 对于任意的序列 比如[1,1,1,3] 他对应0-3-1, 3-2;
. 证明的话, 还不会…

@DELI;

对于有根无向树来说,对于一条边a-b 其实你不需要指定 他俩谁是父节点谁是子节点, 因为给定你一个无向树T (此时他里面任意一条边a-b 你不知道他俩谁是父谁是子), 但是只要给T指定一个根R, 即这个T + R 那么此时 所有的边a-b 他其实就变成了有向边a,b谁是父谁是儿子 此时是固定的! 因为R根是固定了;

@DELI;

對於無向無根樹(不是森林), 假如你要計算他的葉子節點的個數, 對於某個點x 他的鄰接點個數為c, 通常 對葉子節點的定義是: c==1, 而不是c <= 1; (這點的區間 就在於 對於一個只有1個點的樹 這一個點 你到底要不要把他定義為葉子, 這需要你自行決定)

@DELI;

#树上任意两点间 一定且只有1条简单路径#
MARK: @LOC_0;

##推论##: 树上一定有 N + ( N ∗ N − N ) 2 N+ \frac{(N*N - N)}{2} N+2(NNN)条简单路径;
. 因为任选两个点可以确定一条简单路径 我们规定(a <= b)来表示简单路径, 则长度为1的简单路径 即(i,i) 为N个; 长度 > 1 >1 >1的简单路径 由于(a<b) (b>a)有两个 因此 ( N 2 − N ) / 2 (N^2 - N)/2 (N2N)/2个;
. 换句话说 通过for( i = 0; i < N; ++i) for( j = i; j < N; ++j) 即可以遍历所有的简单路径;

@DELI;

#有向树 一定是DAG;#

例题

@LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=140104027;
D[N]满足Di>=1 && Di之和=(N-1)*2的序列, 一定可以对应到 一棵N个点的树的度数;

@DELI;

@LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=133279832
树上路径中 只含有一个特殊点的路径个数

@DELI;

树上回文路径的个数:
LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=131933499;

錯誤

無向樹的遍歷 有一個代碼: dfs(cur,fa){ for(nex){ if(nex!=fa){ dfs(nex,cur);}}}, 這個代碼 非常經典, 過去一直用的都是這個代碼, 但其實 他是有問題的…
假如你的樹 她是有重邊的, 那麼 這個經典代碼 是有大問題的, 一定會超時…
所以 最好的辦法 就是使用通用的 對無向圖的遍歷模板, 即使用一個Vis[]fa參數去掉即可, 每次dfs( cur){ Vis[cur]=1; for(nex){ if(!Vis[nex]){ dfs(nex);}}}, 這個代碼 是絕對正確的 通用的;

算法

删除树的叶节点

@LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=137605680;

树的换根DP

@LINK: https://editor.csdn.net/md/?articleId=133280209;

求任意两点间路径的权值

通过预处理前缀和, a-b路径 可转换为: a-树根的路径 加上 b-树根的路径 减去 2倍的ab的LCA-树根的路径;
LINK: (https://editor.csdn.net/md/?not_checkout=1&articleId=128426984)-(@LOC_0);

筆記

#基础概念#
All basic notions in the Undirected-Graph are also adapted in a Tree (cuz a Tree is also a Undirected-Graph);

--

An Unrooted-Tree (无根树) has several equivalent definitions:
+ An Undirected-Connected-Graph with N N N points and N − 1 N-1 N1 edges;
+ An Undirected-Connected-Graph with no Loop;
+ Any two points have one and only one Simple-Path;
+ Every edge is a Cut-Edge (Bridge);

--

An Rooted-Tree (有根树) is an Unrooted-Tree with an additional designating point r r r called Root;
. One difference to the Unrooted-Tree is that, there is a Hierarchy between any two points;

--

A Forest (森林) is an Undirected-Graph with every Connected-Component be a Tree;
. A Tree is also a Forest;

--

A Leaf-Node (叶子结点):
. 1 In the Unrooted-Tree, it is a point whose Degree ≤ 1 \leq 1 1;
. . Specially, if N = 1 N = 1 N=1, the sole point (whose Degree is 0 0 0) is also a Leaf-Node;
. 2 In the Rooted-Tree, it is a point which has no Child-Node;

--

Simple-Path (简单路径)
. Any two points a , b a,b a,b in a Tree have one and only one Simple-Path a − . . . − b a-...-b a...b
. Therefore, the Distance between any two points is unique;
. In the Rooted-Tree, there must exist one point c c c whose Depth is Least amongst all other points in the path, moreover, ( a − . . . − a 2 − a 1 − c − b 1 − b 2 . . . − b ) (a-...-a_2 - a_1 -c- b_1 -b_2...-b) (a...a2a1cb1b2...b) such that D [ a i ] = D [ b i ] , D [ a i ] = D [ a i + 1 ] − 1 , D [ c ] = D [ a 1 ] − 1 D[a_i] = D[b_i], D[a_i] = D[a_{i+1}] -1, D[c] = D[a_1] - 1 D[ai]=D[bi],D[ai]=D[ai+1]1,D[c]=D[a1]1;
. . We called such point c c c be the Peak (最高点) of the path;

The Distance (距离) between two points is the Value-Sum in the unique Simple-Path between them, it has two types:
. 1 Distance on Point-Value (基于点权的距离), that is all Values are specified by point; (e.g., the Distance of the Simple-Path a − b − c − d a-b-c-d abcd equals V [ a ] + V [ b ] + V [ c ] + V [ d ] V[a] + V[b] + V[c] + V[d] V[a]+V[b]+V[c]+V[d])
. 2 Distance on Edge-Value (基于边权的距离), that is all Values are specified by edge; (e.g., the Distance of the Simple-Path a − b − c − d a-b-c-d abcd equals V [ a − b ] + V [ b − c ] + V [ c − d ] V[a-b] + V[b-c] + V[c-d] V[ab]+V[bc]+V[cd])
. Whichever the case of type, the Distance between any two points is always unique (there is no distinguishing for Maximum or Minimum);

--

The Maximal Simple-Path (Maximal-Path) (a点的最长路径) of a point a a a is the Maximum of D i s t [ a ] [ x ]    ∀ x Dist[a][x] \ \ \forall x Dist[a][x]  x;
. Suppose the Maximal-Path of a a a is [ a , . . . , b ] [a, ..., b] [a,...,b], then b b b maybe not a Leaf-Node (cuz there might exist Negative-Value);
. The similar definition for the Minimal Simple-Path;

--

The Diameter (直径) of a Tree is the Simple-Path whose value equals to the Maximum of the Maximal-Simple-Path for all points (i.e., m a x ( M a x D i s t [ x ] )    ∀ x max( MaxDist[x]) \ \ \forall x max(MaxDist[x])  x);
. The end-points of a Diameter maybe not Leaf-Node (e.g., there exist Negative-Value)

#求所有点的最长路径#

Let 0 0 0 be the root;
. Let D o w n [ x ] Down[x] Down[x] be the Maximal-Distance of x x x that not passing through its Parent-Node (i.e., the Maximal-Distance of x x x in the Sub-Tree rooted by x x x);
. U p [ x ] Up[x] Up[x] be the Maximal-Distance of x x x that must passing through its Parent-Node;
. . The path of U p [ x ] Up[x] Up[x] must be the form [ x , p p , p , s s ] [x, pp, p, ss] [x,pp,p,ss] where p p , s s pp,ss pp,ss are a collection of points, p p , p pp, p pp,p are Ancestor-Node of x x x and p p p is the only points with the Lowest-Depth among all other points, [ p , s s ] [p,ss] [p,ss] is a Path in the Sub-Tree rooted by p p p;
. . That is, start at x x x, then moving up to p p pp pp, and then turn to another child-node of pp;
. Obviously, the Maximal-Distance of x x x equals m a x ( D o w n [ x ] , U p [ x ] ) max( Down[x], Up[x]) max(Down[x],Up[x]);

The brute-method would cost O ( N 2 ) O(N^2) O(N2), here is a O ( N ) O(N) O(N) algorithm;

@Delimiter

Let’s take the example of Distance on Point-Value, A [ ] A[] A[] denotes the Value of points; (it is similar for the case that based on Edge-Value);
. And suppose that a path must contains at least one-point (e.g., all point-values are Negative, then the Maximal-Distance of any point x x x must be < 0 < 0 <0 not = 0 = 0 =0 cuz x x x must contained in the path);

D o w n [ x ] Down[x] Down[x] can be calculated by a DFS dfs_down;

void dfs_down( int cur, int fa){
	Down[ cur] = 0;
	for( nex : $(the adjacent-points of `cur`)){
		if( nex == fa){ continue;}
		dfs_down( nex, cur);
		Down[ _cur] = max( Down[ nex], Down[ _cur]);
	}
	Down[ _cur] += A[ _cur];
}

U p [ x ] Up[x] Up[x] will use another DFS dfs_up( cur, fa, up) where up represents The Maximal-Distance of f a fa fa without passing through c u r cur cur (i.e., the Maximal-Distance of f a fa fa in the Tree with removing the Sub-Tree rooted by c u r cur cur);

             r
(a1,a2)            (a3)
            (b1,b2)     (b3)
                       (c1,c2,c3)

. When we at dfs_up( b3, a3, up), now up would denote the Maximal-Distance of a 3 a3 a3 in the Tree ( r , a 1 , a 2 , a 3 , b 1 , b 2 , b 3 ) (r,a1,a2,a3,b1,b2,b3) (r,a1,a2,a3,b1,b2,b3); so, the Answer of b 3 b3 b3 would be m a x ( U p [ a 3 ] + A [ b 3 ] , D o w n [ b 3 ] ) max( Up[a3] + A[b3], Down[b3]) max(Up[a3]+A[b3],Down[b3]);
. Then, we need do some work for the next dfs_up( ci, b3, up?); let d 1 d1 d1 be the Maximum of D o w n [ c 1 , c 2 , . . . ] Down[c1,c2,...] Down[c1,c2,...] and s o n 1 son1 son1 corresponds to any c i ci ci whose D o w n [ s o n 1 ] = d 1 Down[son1] = d1 Down[son1]=d1, and d 2 d2 d2 be the Maximum of D o w n [ x ]    ∀ x ≠ s o n 1 Down[x] \ \ \forall x \neq son1 Down[x]  x=son1;
. . For the dfs_up( son1, b3, up?) where up? should equal to A [ b 3 ] + m a x ( u p , d 2 ) A[b3] + max( up, d2) A[b3]+max(up,d2);
. . For the dfs_up( $(not son1), b3, up?) where up? should equal to A [ b 3 ] + m a x ( u p , d 1 ) A[b3] + max( up, d1) A[b3]+max(up,d1);

void dfs_up( cur, fa, up){
	Answer[ _cur] = max( up + A[ cur], Down[ _cur]);
	//--
    max_down_1 = 0, max_down_2 = 0;
    son_1;
    for( nex : $(adjacency of `cur`)){
        if( nex == fa){ continue;}
        if( Down[ nex] > max_down_1){
            max_down_2 = max_down_1;
            max_down_1 = Down[ nex];  son_1 = nex;
        }
        else if( Down[ nex] > max_down_2){
            max_down_2 = Down[ nex];
        }
    }
    //--
    for( nex : $(adjacency of `cur`)){
        if( nex == fa){ continue;}
        if( nex != son_1){
            dfs_up( nex, cur, max( up, max_down_1) + A[cur]);
        }
        else{
            dfs_up( nex, cur, max( up, max_down_2) + A[cur]);
        }
    }
}

#至少新添加几条边,使得Tree变成EBCC#
problem-link

Let the number of leaves of the Tree (note not Forest) is m m m; (note that m m m is independent from the root of a tree, here the tree has no root; or in other words, whether it has root or whatever the root is, would not affect m m m)

Let all leaves be a 1 , . . . , a m a1, ..., am a1,...,am (suppose that m > 1 m > 1 m>1)
There must exist a certain permutation of a 1 , . . . , a m a1, ..., am a1,...,am such that after the below process, a tree becomes a E B C C EBCC EBCC.

for( int i = 1; i + 1 <= m; i += 2){
	connect( ai, a_{i+1});
}
if( m & 1){
	connect( am, ax); //< ax is any point [a1,...,a_{m-1}]
}

Cuz all edges on a tree are Cut-Edge, those edges must no longer be Cut-Edge in the new graph;
__. When we connect two leaves a i , a j ai, aj ai,aj, let the edges on the simple-path a i , a j ai, aj ai,aj in the Tree are S S S, then after added the new edge, all edges on S S S are no longer Cut-Edge; therefore, our goal is making all simple-path covers all edges on the tree.
__. T = ( a − b ) ( a − c ) ( b − d ) ( b − e ) ( c − f ) ( c − g ) T= (a-b) (a-c) (b-d) (b-e) (c-f) (c-g) T=(ab)(ac)(bd)(be)(cf)(cg), all leaves are d , e , f , g d,e,f,g d,e,f,g; if we connect ( d − e ) ( f − g ) (d-e) (f-g) (de)(fg) then the edge ( a − b ) (a-b) (ab) is still Cut-Edge; while we connect ( d − g ) ( e − f ) (d-g) (e-f) (dg)(ef) then there would be no Cut-Edge;
Detail Process:

vector<int> Leaf_order;
dfs( int cur, int fa){
	if( `cur` is a leaf){ Leaf_order.push_back( cur);}
	for( `nex` : all adjacent-points of `cur){
		if( nex == fa){ continue;}
		dfs( nex, cur);
	}	
}

r = any Non-Leaf point;
dfs( r);

Then we connect head = 0, tail = m-1; connect( Leaf_order[head ++], Leaf_order[tail --]);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值