"Explanations" Luo Valley P3384 [template] tree chain split

Problem Portal

Portal1: Luogu

Description

As stated, it is known a containing \ (N \) nodes of the tree (and no communication ring), each node comprising a numerical value, needs to support the following operations:

Operation \ (1 \) : Format: 1 x y zshows a tree from x to y values of all nodes in the shortest path are nodes plus \ (Z \) ;

Operation \ (2 \) : Format: 2 x yindicates finding a tree node from x to y value on the shortest path and all the nodes;

Operation \ (3 \) : Format: 3 x zrepresents all nodes will be x values are within the subtree root node plus \ (Z \) ;

Operation \ (4 \) : Format: 4 xindicates finding all nodes within the x value is a root node of the subtree and.

Input

The first line contains \ (4 \) positive integer \ (N \) , \ (M \) , \ (R & lt \) , \ (P \) , each represent the number of tree nodes, the number of operations, root modulo the number and node number ( i.e., all of this output are modulo ).

The next line contains the \ (N \) non-negative integers, represents an initial value sequentially, on each node.

Next \ (N - 1 \) lines contains two integers \ (X \) , \ (Y \) , represents the point \ (X \) and the point \ (Y \) is connected there is an edge between (guaranteed acyclic and communication)

Next \ (M \) lines each comprising a number of positive integers, each row represents an operation, the following format:

Operation \ (1 \) :1 x y z

Operation \ (2 \) :2 x y

Operation \ (3 \) :3 x z

Operation \ (4 \) :4 x

Output

Comprising a plurality of output lines, respectively, sequentially illustrating each operation \ (2 \) or operation \ (4 \) The results obtained (p \ (P \) modulo).

Sample Input

5 5 2 24
7 3 7 8 0 
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3

Sample Output

2
21

Solution

Template tree chain split title.

Some concepts:

  • Son weight: a maximum of in each non-leaf node sons, son node to the root of the subtree of nodes for node weight son son point;

  • Light son: in a non-leaf, heavy non-son node;

  • Multiple edges: a father node connecting edge has a weight sons;

  • Light Edge: non-reentrant edge;

  • Heavy chain: Heavy adjacent edges connected together, the connection node of one heavy chain son called heavy chain.

dfs1Features:

  • Obtaining depth of each node;

  • Obtaining a parent node of each node;

  • Determined size of each non-leaf sub-tree node;

  • Find each weighing son of a non-leaf node number.

dfs2Features:

  • Each processing chain;

  • The new tag ID of each node;

  • Obtaining each of the top node where the chain;

  • The initial value of the node to the new number in the updated.

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>

using namespace std;

const int MAXN = 2000005;
struct EDGE {
    int u, v, nxt;
} edge[MAXN];
struct node {
    int l, r, w, size, f;
} tree[MAXN];
int n, m, root, mod, cnt, num = 1, a[MAXN], b[MAXN], tot[MAXN], son[MAXN], top[MAXN], idx[MAXN], dep[MAXN], head[MAXN], father[MAXN];
inline void addedge(int u, int v) {
    edge[num].u = u; edge[num].v = v; edge[num].nxt = head[u]; head[u] = num++;
}
//dep[i]表示i结点的深度
//father[i]表示i结点的父亲结点
//son[]表示重儿子的编号
inline int dfs1(int now, int f, int deep) {
    dep[now] = deep;
    father[now] = f;
    tot[now] = 1;
    int Maxson = -1;
    for (int i = head[now]; ~i; i = edge[i].nxt) {
        if (edge[i].v == f) continue;
        tot[now] += dfs1(edge[i].v, now, deep + 1);
        if (tot[edge[i].v] > Maxson) {
            Maxson = tot[edge[i].v];
            son[now] = edge[i].v;
        }
    }
    return tot[now];
}
inline void dfs2(int now, int topf) {
    idx[now] = ++cnt;
    a[cnt] = b[now];
    top[now] = topf;
    if (!son[now]) return ;
    dfs2(son[now], topf);
    for (int i = head[now]; ~i; i = edge[i].nxt)
        if (!idx[edge[i].v]) dfs2(edge[i].v, edge[i].v);
}
inline void pushup(int root) {
    tree[root].w = (tree[root << 1].w + tree[root << 1 | 1].w + mod) % mod;
}
inline void build(int root, int l, int r) {
    tree[root].l = l; tree[root].r = r; tree[root].size = r - l + 1;
    if (l == r) {
        tree[root].w = a[l];
        return ;
    }
    int mid = l + r >> 1;
    build(root << 1, l, mid);
    build(root << 1 | 1, mid + 1, r);
    pushup(root);
}
inline void pushdown(int root) {
    if (!tree[root].f) return ;
    tree[root << 1].w = (tree[root << 1].w + tree[root << 1].size * tree[root].f) % mod;
    tree[root << 1 | 1].w = (tree[root << 1 | 1].w + tree[root << 1 | 1].size * tree[root].f) % mod;
    tree[root << 1].f = (tree[root << 1].f + tree[root].f) % mod;
    tree[root << 1 | 1].f = (tree[root << 1 | 1].f + tree[root].f) % mod;
    tree[root].f = 0;
}
inline void update_add(int root, int ansl, int ansr, int val) {
    if (ansl <= tree[root].l && tree[root].r <= ansr) {
        tree[root].w += tree[root].size * val;
        tree[root].f += val;
        return ;
    }
    pushdown(root);
    int mid = tree[root].l + tree[root].r >> 1;
    if (ansl <= mid) update_add(root << 1, ansl, ansr, val);
    if (ansr > mid) update_add(root << 1 | 1, ansl, ansr, val);
    pushup(root);
}
//线段树操作
inline void tree_add(int x, int y, int val) {
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        update_add(1, idx[top[x]], idx[x], val);
        x = father[top[x]];
    }
    if (dep[x] > dep[y]) swap(x, y);
    update_add(1, idx[x], idx[y], val);
}
inline int query_sum(int root, int ansl, int ansr) {
    int ret = 0;
    if (ansl <= tree[root].l && tree[root].r <= ansr) return tree[root].w;
    pushdown(root);
    int mid = tree[root].l + tree[root].r >> 1;
    if (ansl <= mid) ret = (ret + query_sum(root << 1, ansl, ansr)) % mod;
    if (ansr > mid) ret = (ret + query_sum(root << 1 | 1, ansl, ansr)) % mod;
    return ret;
}
inline void tree_sum(int x, int y) {
    int ret = 0;
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        ret = (ret + query_sum(1, idx[top[x]], idx[x])) % mod;
        x = father[top[x]];
    }
    if (dep[x] > dep[y]) swap(x, y);
    ret = (ret + query_sum(1, idx[x], idx[y])) % mod;
    printf("%d\n", ret);
}
int main() {
    memset(head, -1, sizeof(head));
    scanf("%d%d%d%d", &n, &m, &root, &mod);
    for (int i = 1; i <= n; i++)
        scanf("%d", &b[i]);
    for (int i = 1; i < n; i++) {
        int x, y;
        scanf("%d%d", &x, &y);
        addedge(x, y);
        addedge(y, x);
    }
    dfs1(root, 0, 1);
    dfs2(root, root);
    build(1, 1, n);
    while (m--) {
        int opt, x, y, val;
        scanf("%d", &opt);
        if (opt == 1) {
            scanf("%d%d%d", &x, &y, &val);
            val %= mod;
            tree_add(x, y, val);
        } else
        if (opt == 2) {
            scanf("%d%d", &x, &y);
            tree_sum(x, y);
        } else
        if (opt == 3) {
            scanf("%d%d", &x, &val);
            update_add(1, idx[x], idx[x] + tot[x] - 1, val % mod);
        } else {
            scanf("%d", &x);
            printf("%d\n", query_sum(1, idx[x], idx[x] + tot[x] - 1));
        }
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/shenxiaohuang/p/11221128.html