Special Data Structure: Partition Tree chain

Special Data Structure: Partition Tree chain

For a given root node of the tree, if that we now find a way to complete the following four operations:

1. The tree \ (X-\) to \ (the Y \) weights of all nodes in the shortest path are nodes plus \ (the Z \) .

2. seeking tree \ (X-\) to \ (the Y \) and the weights of all the nodes on the shortest path node values.

3. will \ (X-\) is the weight of all the nodes in the subtree root node value plus \ (the Z \) .

4. In seeking \ (X-\) right to all nodes within a subtree root node and the sum of the values.

First talk about violence, then we might think of doubling \ (LCA \) , if in fact without modification, then \ (O (logN) \) multiplication can be said to be a very good. But for this modification of 1,3 addition to violence requires us to basically no other way, it is not our request.

We therefore leads to cross tree a chain of argument, that is, the tree split chain , which is a kind of tree can be transformed into linear very powerful data structure.

First of all we need to know before you explain some of the concepts inside:

  1. Heavy son: for node \ (U \) of all child nodes \ (T \) , if \ (T_i \) the size of the largest sub-tree, called \ (T_i \) to \ (U \) heavy son.
  2. Light Son: As the rest of the child nodes are sons of light.
  3. Multiple edges: node \ (U -> T_i \) This side is the heavy side ( \ (T_i \) to \ (U \) re-son)
  4. Light Edge: As the rest of the edges are light side.
  5. Heavy chain: adjacent to link all the heavy side is the heavy chain. For a leaf node if it is light son, it is itself both a chain.

Obviously for any leaf nodes are not heavy or light the son of the son. Here are a picture for us to understand perhaps.

1560346268187

All the red dot boxed figure is a heavy chain.

So we have a demand for a solution to the above.

Operation 1: For two points \ (X-\) , \ (the Y \) , we first chain belongs depth larger chain as \ (X-\) , then if the two point is not inside a chain we put \ (X-\) to \ (X-\) weights for all points of the first chain strand are modified belongs, \ (the Y \) is the same. Until \ (X \) and \ (Y \) belong to the same chain, we put \ (X \) to \ (Y \) All weights points on the path are modifying it.

And this section is for what? You can find our tree-operation became operational on several chains. The operation of the chain we can be very simple to use segment tree or a tree array for maintenance. Similarly operating the following two methods are applied directly above query.

As for the operation of 3,4 it? We will conduct two tree traversal, the purpose is to obtain the information we need in order to achieve, for example:

Change point at which the top strand: Top

Size: sub-tree size (including its own

Deep: node depth

Fa: parent node.

Son: Heavy son

Id: this thing called the Dfs order, is to use the tree line and we will re-number the whole tree a little row of new numbers each node.

V: This is the weight of the new point number.

Let's look at two specific Dfs:

int Deep[MAXN], Fa[MAXN], Size[MAXN], Son[MAXN] ;
inline void Dfs1(int Now, int Fas, int Deeps) {
    Deep[Now] = Deeps, Fa[Now] = Fas, Size[Now] = 1 ;
    int Maxson = - 1 ;
    for (int i = H[Now] ; i ; i = E[i].Next) {
        if (E[i].T == Fas) continue ;
        Dfs1(E[i].T, Now, Deeps + 1) ;
        Size[Now] += Size[E[i].T] ;
        if (Size[E[i].T] > Maxson)
            Son[Now] = E[i].T, Maxson = Size[E[i].T] ;
    }
}

int Id[MAXN], Top[MAXN], Cnt ;
inline void Dfs2(int Now, int Tops) {
    Id[Now] = ++ Cnt, V[Cnt] = W[Now], Top[Now] = Tops ;
    if (! Son[Now]) return ;
    Dfs2(Son[Now], Tops) ;
    for (int i = H[Now] ; i ; i = E[i].Next) {
        if (E[i].T == Fa[Now] || E[i].T == Son[Now])
            continue ;
        Dfs2(E[i].T, E[i].T) ;
    }
}

Then for a Dfs above sample image sequence is:

1560347005994

This is obviously very simple. So we are talking about operating above 1,2 and very obvious.

inline int Range(int X, int Y) {
    int Ans = 0 ;
    while (Top[X] != Top[Y]) {
        if (Deep[Top[X]] < Deep[Top[Y]] ) swap(X, Y) ;
        int Res = Query(1, Id[Top[X]], Id[X]) ;
        Ans = (Ans + Res) % Mod ; X = Fa[Top[X]] ;
    }
    if (Deep[X] > Deep[Y]) swap(X, Y) ;
    int Res = Query(1, Id[X], Id[Y]) ;
    Ans += Res ; return Ans % Mod ;
}
inline void Change(int X, int Y, int K) {
    K %= Mod ;
    while (Top[X] != Top[Y]) {
        if (Deep[Top[X]] < Deep[Top[Y]]) swap(X, Y) ;
        SegChange(1, Id[Top[X]], Id[X], K) ;
        X = Fa[Top[X]] ;
    }
    if (Deep[X] > Deep[Y]) swap(X, Y) ;
    SegChange(1, Id[X], Id[Y], K) ;
}

Then for 3,4 operations, we talk about a certain point all the weights of all the descendants of modification, according to Dfs Dfs sequence order we can know at this point and all its descendants must be a continuous \ (Id [Now] - > Id [Now] + Size [Now] - 1 \) , then we can also maintain a direct line with the tree.

inline int GetSon(int Now) {
    return Query(1, Id[Now], Id[Now] + Size[Now] - 1) % Mod ;
}
inline void Point(int Now, int K) {
    SegChange(1, Id[Now], Id[Now] + Size[Now] - 1, K % Mod) ;
}

The above \ (Segchange \) and \ (query \) are the most basic operating segment tree, I do not think were deliberately explained.

The total time complexity of it? All operations are the segment tree \ (O (logN) \) , but we are also cross-sectional tree operation \ (O (logN) \) , then the entire tree chain split time complexity is \ (O ( ^ 2N log) \) , but more than \ (LCA \) query + modify violence is much more superior it.

The following code template theme Luo Gu is given. Link

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#define LS (Now << 1)
#define RS ((Now << 1) | 1)
#define Mid ((L + R) >> 1)
#define E_Mid ((G[Now].L + G[Now].R) >> 1)

using namespace std ;
typedef long long LL ;
const int MAXN = 200010, MAXM = 400010 ;
const int Inf = 0x7fffffff ;

int N, M, Root, Mod, H[MAXN], Tot, V[MAXN] ;
struct EDGE {
    int F, T, Next ;
}   E[MAXM << 1] ;
int W[MAXN], Wt[MAXN] ;

inline int Read() {
    int X = 0, F = 1 ; char ch = getchar() ;
    while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;
    while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
    return X * F ;
}

inline void Add(int F, int T) {
    E[++ Tot].F = F ; E[Tot].T = T ;
    E[Tot].Next = H[F], H[F] = Tot ;
}

struct TREE {
    int L, R, Sum, Tag ;
}   G[MAXN << 1] ;
inline void Push_Up(int Now) {
    G[Now].Sum = (G[LS].Sum + G[RS].Sum) % Mod ;
}

inline void Push_Down(int Now) {
    if (G[Now].Tag) {
        G[LS].Tag += G[Now].Tag ; G[RS].Tag += G[Now].Tag ;
        (G[LS].Sum += G[Now].Tag * (G[LS].R - G[LS].L + 1)) %= Mod ;
        (G[RS].Sum += G[Now].Tag * (G[RS].R - G[RS].L + 1)) %= Mod ;
        G[Now].Tag = 0 ;
    }   return ;
}

inline void Build_Tree(int Now, int L, int R) {
    G[Now].L = L ; G[Now].R = R ;
    if (G[Now].L == G[Now].R) {
        G[Now].Sum = V[L] ;
        if (G[Now].Sum > Mod) G[Now].Sum %= Mod ;
        return ;
    }
    Build_Tree(LS, L, Mid), Build_Tree(RS, Mid + 1, R) ;
    Push_Up(Now) ;
}

inline void SegChange(int Now, int L, int R, int K) {
    if (G[Now].L >= L && G[Now].R <= R) {
        G[Now].Sum += K * (G[Now].R - G[Now].L + 1) ;
        G[Now].Tag += K ;
        return ;
    }   Push_Down(Now) ;
    if (L <= E_Mid) SegChange(LS, L, R, K) ;
    if (R > E_Mid)  SegChange(RS, L, R, K) ;
    Push_Up(Now) ;  return ;
}

inline int Query(int Now, int L, int R) {
    if (G[Now].L >= L && G[Now].R <= R)
        return G[Now].Sum % Mod ;
    Push_Down(Now) ; int Ans = 0 ;
    if (E_Mid >= L) Ans = Ans + Query(LS, L, R) % Mod ;
    if (E_Mid < R)  Ans = Ans + Query(RS, L, R) % Mod ;
    return Ans % Mod ;
}

int Deep[MAXN], Fa[MAXN], Size[MAXN], Son[MAXN] ;
inline void Dfs1(int Now, int Fas, int Deeps) {
    Deep[Now] = Deeps, Fa[Now] = Fas, Size[Now] = 1 ;
    int Maxson = - 1 ;
    for (int i = H[Now] ; i ; i = E[i].Next) {
        if (E[i].T == Fas) continue ;
        Dfs1(E[i].T, Now, Deeps + 1) ;
        Size[Now] += Size[E[i].T] ;
        if (Size[E[i].T] > Maxson)
            Son[Now] = E[i].T, Maxson = Size[E[i].T] ;
    }
}

int Id[MAXN], Top[MAXN], Cnt ;
inline void Dfs2(int Now, int Tops) {
    Id[Now] = ++ Cnt, V[Cnt] = W[Now], Top[Now] = Tops ;
    if (! Son[Now]) return ;
    Dfs2(Son[Now], Tops) ;
    for (int i = H[Now] ; i ; i = E[i].Next) {
        if (E[i].T == Fa[Now] || E[i].T == Son[Now])
            continue ;
        Dfs2(E[i].T, E[i].T) ;
    }
}

inline int Range(int X, int Y) {
    int Ans = 0 ;
    while (Top[X] != Top[Y]) {
        if (Deep[Top[X]] < Deep[Top[Y]] ) swap(X, Y) ;
        int Res = Query(1, Id[Top[X]], Id[X]) ;
        Ans = (Ans + Res) % Mod ; X = Fa[Top[X]] ;
    }
    if (Deep[X] > Deep[Y]) swap(X, Y) ;
    int Res = Query(1, Id[X], Id[Y]) ;
    Ans += Res ; return Ans % Mod ;
}

inline int GetSon(int Now) {
    return Query(1, Id[Now], Id[Now] + Size[Now] - 1) % Mod ;
}

inline void Change(int X, int Y, int K) {
    K %= Mod ;
    while (Top[X] != Top[Y]) {
        if (Deep[Top[X]] < Deep[Top[Y]]) swap(X, Y) ;
        SegChange(1, Id[Top[X]], Id[X], K) ;
        X = Fa[Top[X]] ;
    }
    if (Deep[X] > Deep[Y]) swap(X, Y) ;
    SegChange(1, Id[X], Id[Y], K) ;
}

inline void Point(int Now, int K) {
    SegChange(1, Id[Now], Id[Now] + Size[Now] - 1, K % Mod) ;
}

int main() {
    N = Read() ; M = Read() ; Root = Read() ; Mod = Read() ;
    for (int i = 1 ; i <= N ; i ++) W[i] = Read() ;
    for (int i = 1 ; i <  N ; i ++) {
        int A = Read(), B = Read() ;
        Add(A, B) ; Add(B, A) ;
    }
    Dfs1(Root, 0, 1) ; Dfs2(Root, Root) ; Build_Tree(1, 1, N) ; 
    for (int i = 1 ; i <= M ; i ++) {
        int Opt = Read(), X, Y, Z ; switch (Opt) {
            case 1: X = Read(), Y = Read(), Z = Read(), Change(X, Y, Z) ; break ;
            case 2: X = Read(), Y = Read(), printf("%d\n", Range(X, Y)) ; break ;
            case 3: X = Read(), Z = Read(), Point(X, Z) ; break ;
            case 4: X = Read(), printf("%d\n", GetSon(X)) ; break ;
        }
    }   return 0 ;
}

Guess you like

Origin www.cnblogs.com/Yeasio-Nein/p/TCS.html