Graph Theory B Minor Themes

2 tree

2.1 Definition of the tree

Only a \ (N-1 \) edges, and any two points of FIG communication tree is called. There are unrooted tree by tree so defined, and we often arbitrarily selected so that it becomes a root node rooted tree. Rooted tree can be defined "Father and Son" hierarchical relationship, which tends to favor optimal substructure construction, DP and conduct search operations.

In particular, if any of the tree plus one side, then the whole tree will be more of a ring. We call this tree is the "ring tree." Cycloalkyl group tree is not a tree, but it is only one of the rings. The entire ring as a "generalized root", then the subtree root and attached separately on the ring, the same algorithm can be applied in many trees.

2.2 tree algorithm DP

Typically select a root, and then calculated using DFS. As for the interface should be placed before the recursive transfer or after it? Then it looks at how to write equations. When writing a program, as long as the "known unknown push" principle on the line.

Given an unrooted trees, required to give the best answer to a value such that the root optimization, you can use this "for root method." A first arbitrarily selected root planning computed value \ (of F_1 \) , and then mathematically derived from the arbitrary point to the root planning value \ (F_2 \) . There are relevant examples on the "Advanced Guide."

Parameters 2.2.1 tree

Subtree size size
most basic amount. Transfer equation is abbreviated as \ (F (x) = 1 + \ sum F (\ text {son} (x)) \)
the center of gravity of the tree
as and size. If the subtree \ (X \) size is \ (\ text {size} (X) \) , then the rest of the tree is the size of \ (N-\ text {size} (X) \) . In seeking \ (\ text {size} \ ) when passing can be determined.
The diameter of the tree
there is a DP equation, there is a search method.

The first method, set \ (F_1 (x) \) represents the point (X \) \ to its subtree longest distance. We have the equation:
\ [of F_1 (X) = \ {max_ Y \ in \ {text} Son (X)} \ {F. (Y) + D (X, Y) \} \]
then derived through this \ ( X \) in \ (X \) longest chain within the subtree. It is set to \ (F_2 (the X-) \) .
By definition, we had to find out in two sub-tree inside \ (x \) path, the longest two paths that meet the requirements. Have the equation:
\ [F_2 (X) = \ max_ {Y_1, Y_2 \ in \ text {Son} (X)} \ {of F_1 (Y_1) + D (X, Y_1) + of F_1 (Y_2) + D (X, y_2) \} \]
these two values, the maximum value is a constant, a certain time is a large value. We The \ (of F_1 \) defined, to give:
\ [F_2 (X) = \ max_ {Y_2 \ in \ text {Son} (X), Y_2 \ NEQ Y_1, of F_1 (X) = F. (Y_1) + D (x, y_1)} \ {
F_1 (x) + F_1 (y_2) + d (x, y_2) \} \] such equation would be cumbersome. We put it another idea:
set \ (F_1 (x) \) represents \ (x \) to \ (x \) the maximum distance from the child leaves,\ (G_1 (x) \) represents the second largest distance. So we have two equations:
\ [\ Cases} {G_1 the begin (X) of F_1 = (X), of F_1 (X) of F_1 = (Y) + D (X, Y) of F_1 & (X) <of F_1 (Y) + d (x, y) \\ G_1 (x) = F_1 (y) + d (x, y) & \ text {else if} G_1 (x) <F_1 (y) + d (x, y) \ end {cases} \\ y \ in \
text {son} (x) \] so \ (F_2 (x) = G_1 (x) + F_1 (x) \) is the originally required. Enumeration biggest \ (F (i) \) can be obtained answer.

It can also be used twice BFS or DFS. To any point \ (the root \) , from the search \ (the root \) furthest point \ (P_1 \) ; then searched from the \ (P \) point furthest point \ (P '\) . Then the distance between two points \ (pp '\) in diameter that tree.

2.2.2 LCA

If the node \ (u \) both \ (x \) ancestors, but also \ (y \) ancestors, then \ (u \) is \ (x, y \) of a common ancestor. When the depth of the deepest common ancestor, the mind \ (u = LCA (x, y) \) is \ (x, y \) a common ancestor.
There are several methods seeking LCA:

Up notation \ (O (qN) \)
for the required \ (the LCA (X, Y) \) , we first choose a node \ (X \) come to the root node, the point on the path of all markers. Then, we let \ (y \) at the same time going up, \ (y \) first marked point encountered is \ (LCA (the X-, the y-) \) .

Method multiplication tree \ (O (q \ log N
) \) First we set \ (F (x, i) \) represents \ (X \) a \ (2 ^ i \) generation ancestor, i.e. \ (X \) go up \ (2 ^ i \) node obtained in step. Initial when \ (F. (X, 0) = \ text {Father} (X) \) , then \ (I \) is the stage to \ (F (x, i) = F (F (x, i - 1), i - 1) \) for the transfer equations, we can handle all of the \ (F. (X, I) \) .

Next we choose a point jump up (this set point \ (the X-\) ). May be exchanged such that \ (\ {text} Deep (X) \ GEQ \ {text} Deep (Y) \) . Sequentially try to get \ (X \) go up \ (2 ^ {\ log N }, \ cdots, 2 ^ 2,2 ^ 1,2 ^ 0 \) step, so that each step just to meet \ (\ text {deep } (X) \ GEQ \ {text} Deep (Y) \) . The last step should \ (\ {text} Deep (X) = \ {text} Deep (Y) \) . If \ (X = Y \) , then the \ (the LCA (X, Y) = Y \) .

Otherwise, we let \ (X \) , \ (Y \) simultaneously jump up \ (2 ^ {\ log N }, \ cdots, 2 ^ 2,2 ^ 1,2 ^ 0 \) step, so that each step there \ (the X-\ neq the y-\) . In the final step, we must have \ (\ {text} Father (X) = \ {text} Father (Y) = the LCA (X, Y) \) .

Trees doubling method has a very wide range of applications. For example, the question will need to maintain proper way the maximum path of the tree, then you can use "tree table ST." This structure is reflected in the tree multiplication method.

Chain split tree \ (O (q \ log N
) \) key dfs is treated twice with an toparray, i.e. the top strand of each tree. Each time asked if \ (x \) and \ (y \) are on the same chain, the \ (LCA (x, y) \) is a smaller depth of that node. Otherwise, we let nodes to a greater depth above its chain jump, and even if \ (X = \ {text} Father (\ {text} Top (X)) \) .

Implement the code length is longer, there will be some constant, but the time complexity of the above should still slightly better than doubling method. This method and scalable, can support other operations.

LCA of Tarjan algorithm \ (O (q + N)
\) with disjoint-set up to optimize the notation.

DFS when searching a tree, each node has three states: UNMARKED, TRAVERSALand BACKTRACKEDeach is "untagged", "traversed", "has been back."
When a node \ (X \) is in a TRAVERSALstate, it must be the root node along a father to a TRAVERSALchain. In any case for BACKTRACKEDa node state \ (Y \) , \ (the LCA (X, Y) \) is \ (Y \) a first path along a father, encountered TRAVERSALnode. This is the essence of upward notation.
Here for UNMARKEDthe \ (Y \) is not established, since the TRAVERSALchain and BACKTRACKEDthe intersection of chain branching corresponds to a different decision time, so the first \ (X \) and \ (Y \) a separate node. Otherwise, along \ (y \) section of the path will be marked TRAVERSALinstead BACKTRACKED.

Here, we use a disjoint-set to maintain this path. For a BACKTRACKEDnode, we define its fulcrum \ (top (y) \) represents node \ (y \) along the path of his father, the first encounter upward TRAVERSALnode.
When a node \ (X \) a TRAVERSALbecomes BACKTRACKED, it must be the father TRAVERSALof (can be obtained according to the order of traversal back). In this case there must be \ (Top (X) = Top (\ {text} Father (X)) \) .
When we visit \ (top (y) \) , the path may be the way to compress that \ (Top (the y-) = Top (Top (the y-)) \) . This is no impact on the answer. This disjoint-set and the like, can be used to check and set getoperation is completed.

In summary, for each UNMARKEDnode \ (the X-\) , we first mark TRAVERSAL, and traverse its son \ (the y-\) , then make \ (Top (the y-) = the X-\) . Then, for each and (x \) \ an inquiry about \ (LCA (u_i, the X-) \) , if \ (u_i \) is BACKTRACKED, we can directly get(u[i])get the answer.
The interrogation queries regarding offline processing, pre-processing, and each node, and then run the algorithm. Time complexity \ (O (N + Q) \) , and wherein the set of search time and complexity is negligible.


unsigned short state[MAXN];
#define UNMARKED 0
#define TRAVERSAL 1
#define BACKTRACKED 2

int top[MAXN];
inline int get(int cur)
{
    if(cur == top[cur])
        return cur;
    return top[cur] = get(top[cur]);
}
inline void init()
{
    for(rg int i = 1; i <= N; ++ i)
        top[i] = i;
}

void DFS(int cur)
{
    state[cur] = TRAVERSAL;
    for(rg int e = head[cur]; e; e = edge[e].next)
    {
        int to = edge[e].to;
        if(state[to] != UNMARKED)
            continue;
        DFS(to);
        top[to] = cur;
    }
    
    for(rg int i = 0; i < queryNode[cur].size(); ++ i)
    {
        int node = queryNode[cur][i], rank = queryRank[cur][i];
        if(state[node] != BACKTRACKED)
            continue;
        ans[rank] = get(node);
    }
    state[cur] = BACKTRACKED;
}

Guess you like

Origin www.cnblogs.com/LinearODE/p/11324746.html