首页 > 其他分享 >P3384 【模板】重链剖分/树链剖分 - SGT && 重链剖分

P3384 【模板】重链剖分/树链剖分 - SGT && 重链剖分

时间:2024-02-17 20:55:59浏览次数:33  
标签:sx 剖分 int top SGT dep ans 重链 id

本题是非常非常非常纯粹的树剖,利用了重链剖分后下标的性质

不多说上代码就好了

#include <cstdio>
#include <vector>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
int n, m, r;
ll p, a[N], b[N];
vector <int> V[N];
int fa[N], dep[N], siz[N], hson[N], id[N], cnt, top[N];
void dfs1(int sx, int ffa) {
    fa[sx] = ffa;
    dep[sx] = dep[ffa] + 1;
    int maxn = -1;
    siz[sx] = 1;
    for (auto to : V[sx]) {
        if (to == ffa) continue;
        dfs1(to, sx);
        siz[sx] += siz[to];
        if (siz[to] > maxn) {
            maxn = siz[to];
            hson[sx] = to;
        }
    }
}
void dfs2(int sx, int topf) {
    id[sx] = ++ cnt;
    top[sx] = topf;
    b[cnt] = a[sx] % p;
    if (hson[sx])
        dfs2(hson[sx], topf);
    for (auto to : V[sx]) {
        if (to == fa[sx] || to == hson[sx]) continue;
        dfs2(to, to);
    }
}
struct sgt {
    ll sum[N << 2], lz[N << 2];
    void PushUp(int u) {
        sum[u] = (sum[u << 1] + sum[u << 1 | 1]) % p;
        return ;
    }
    void build(int u, int l, int r) {
        lz[u] = 0;
        if (l == r) {
            sum[u] = b[l];
            return ;
        }
        int mid = l + r >> 1;
        build (u << 1, l, mid);
        build (u << 1 | 1, mid + 1, r);
        PushUp (u);
        return ;
    }
    void PushDown(int u, int s) {
        if (lz[u] == 0) return ;
        (lz[u << 1] += lz[u]) %= p;
        (lz[u << 1 | 1] += lz[u]) %= p;
        (sum[u << 1] += lz[u] * (s - (s >> 1))) %= p;
        (sum[u << 1 | 1] += lz[u] * (s >> 1)) %= p;
        lz[u] = 0;
        return ;
    }
    void modify(int u, int l, int r, int L, int R, ll k) {
        if (L <= l && r <= R) {
            (sum[u] += k * (r - l + 1)) %= p;
            (lz[u] += k) %= p;
            return ;
        }
        PushDown (u, r - l + 1);
        int mid = l + r >> 1;
        if (L <= mid)
            modify (u << 1, l, mid, L, R, k);
        if (mid < R)
            modify (u << 1 | 1, mid + 1, r, L, R, k);
        PushUp (u);
        return ;
    }
    ll query(int u, int l, int r, int L, int R) {
        if (L <= l && r <= R)
            return sum[u];
        PushDown(u, r - l + 1);
        ll ans = 0;
        int mid = l + r >> 1;
        if (L <= mid)
            ans += query(u << 1, l, mid, L, R);
        if (mid < R)
            ans += query(u << 1 | 1, mid + 1, r, L, R);
        return ans % p;
    }
    void mod_1(int x, int y, ll k) {
        while (top[x] != top[y]) {
            if (dep[top[x]] > dep[top[y]]) {
                modify (1, 1, n, id[top[x]], id[x], k);
                x = fa[top[x]];
            }
            else {
                modify (1, 1, n, id[top[y]], id[y], k);
                y = fa[top[y]];
            }
        }
        if (dep[x] > dep[y])
            modify (1, 1, n, id[y], id[x], k);
        else modify (1, 1, n, id[x], id[y], k);
        return ;
    }
    ll que_1(int x, int y) {
        ll ans = 0;
        while (top[x] != top[y]) {
            if (dep[top[x]] > dep[top[y]]) {
                // ans = (ans + query (1, 1, n, id[top[x]], id[x])) % p;
                (ans += query (1, 1, n, id[top[x]], id[x])) %= p;
                x = fa[top[x]];
            }
            else {
                // ans = (ans + query (1, 1, n, id[top[y]], id[y])) % p;
                (ans += query (1, 1, n, id[top[y]], id[y])) %= p;
                y = fa[top[y]];
            }
        }
        if (dep[x] > dep[y])
            // ans = (ans + query (1, 1, n, id[y], id[x])) % p;
            (ans += query (1, 1, n, id[y], id[x])) %= p;
        else /*ans = (ans + query (1, 1, n, id[x], id[y])) % p;*/
        (ans += query (1, 1, n, id[x], id[y])) %= p;
        return ans % p;
    }
}tre;
int main() {
    // freopen ("tmp.out", "w", stdout);
    scanf ("%d%d%d%lld", &n, &m, &r, &p);
    for (int i = 1;i <= n; ++ i)
        scanf ("%lld", a + i);
    for (int i = 1;i < n; ++ i) {
        int u, v;
        scanf ("%d%d", &u, &v);
        V[u].push_back(v);
        V[v].push_back(u);
    }
    dfs1(r, r);
    dfs2(r, r);
    tre.build(1, 1, n);
    while (m --) {
        int opt;
        scanf ("%d", &opt);
        if (opt == 1) {
            int x, y;
            ll z;
            scanf ("%d%d%lld", &x, &y, &z);
            tre.mod_1 (x, y, z);
            continue;
        }
        if (opt == 2) {
            int x, y;
            scanf ("%d%d", &x, &y);
            printf ("%lld\n", tre.que_1 (x, y));
            continue;
        }
        if (opt == 3) {
            int x;
            ll k;
            scanf ("%d%lld", &x, &k);
            tre.modify(1, 1, n, id[x], id[x] + siz[x] - 1, k);
            continue;
        }
        if (opt == 4) {
            int x;
            scanf ("%d", &x);
            printf ("%lld\n", tre.query(1, 1, n, id[x], id[x] + siz[x] - 1));
            continue;
        }
    }
    return 0;
}

标签:sx,剖分,int,top,SGT,dep,ans,重链,id
From: https://www.cnblogs.com/Assassins-Creed/p/18018380

相关文章

  • P3038 [USACO11DEC] Grass Planting G - 重链剖分
    本题可以说是板题P3384的弱化版,只不过要改的变成了边权边权很好处理,只需要将每个边的边权下放到两端点深度比较深的上面就好了(因为每个点连比它浅的节点必定只有一条边)。那么就将模板改一下就好了代码如下:#include<cstdio>usingnamespacestd;constintN=1e5+5;in......
  • 树链剖分
    树链剖分分为重链剖分和长链剖分重链剖分首先是重链剖分,树链剖分顾名思义是一种将代码大小增加1k树剖成一条条链的方法。定义:重儿子该节点所有儿子中以该儿子为根的子树最大的儿子重边连接该节点与该节点的重儿子的那条边重链由根节点或一个轻儿子为链头一路重边连到叶......
  • 树链剖分
    看逆天算法,品百味OI#41.重链剖分给出如下定义:重子结点:一个点的子节点中子树最大的点轻子节点:剩余的子节点重边:该节点到重子节点的边轻边:到轻子节点的边重链:若干条首尾相接的重边预处理由两个DFS实现DFS1:记录节点的父节点、深度、子树大小、重子结点DFS......
  • 重链剖分
    重链剖分优先走重儿子,路径跳不超过\(O(\logn)\)intsiz[N],fa[N],dep[N],top[N],dfn[N],hson[N],dfc;//注意每个都要处理voiddfs1(intx,intFa){ fa[x]=Fa; siz[x]=1; hson[x]=0; for(inti=h[x];i;i=e[i].ne){ inty=e[i].to; if(y==Fa)continue; dep[y]=dep[......
  • 树链剖分学习笔记
    树链剖分,计算机术语,指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结构(树状数组、BST、SPLAY、线段树等)来维护每一条链。——百度百科重链剖分概念1重儿子一个父节点的所有儿子中,子树节点最大(siz最大)的节点。记......
  • 链剖分
    重链剖分第一次DFS求重儿子(子节点更多的儿子)。第二次DFS求重链剖分(先访问重儿子再访问其他轻儿子)。变量:重儿子,子树大小,DFS序(\(x\)根子树DFS序中第一次出现位置),以\(x\)为根的子树的最后一次出现位置,深度,\(x\)所在重链的顶端。voiddfs1(intx){//求出重儿子,sz[v]......
  • 树链剖分
    son[x]表示节点\(x\)的重儿子,若为\(0\),则说明\(x\)为叶子节点id[x]表示节点\(x\)的dfs序编号f[x]表示节点\(x\)的父节点dep[x]表示节点\(x\)的深度sz[x]表示节点为\(x\)的子树的大小top[x]表示x所在重链顶部的节点函数原型voiddfs1(llu,llfa)功能:计算dep[]、f[]、sz[]和......
  • 【动态规划】长链剖分优化树形 dp
    我们在树形dp中经常会遇到这样一个模型:设\(f_{x,i}\)表示节点\(x\)的子树中深度为\(x\)的答案...有递推式:\(f_{x,i}=\sum_{son}f_{son,i-1/i+1}\dots\)。这样直接做是\(\Theta(n^2)\)的,我们考虑去优化这个dp。有一个小优化,就是我们想让\(f_x\)直接继承......
  • 【树链剖分】P3401 洛谷树 题解
    P3401考虑先将路径权值进行转化,因为很难对路径直接进行统计。考虑如何表示出这条路径的权值。记\(s_i=\oplus_{j\in\text{path}(1,i)}w_j\),其中\(\text{path}(i,j)\)表示\(i\)到\(j\)的路径上的边集。则\(u\tov\)的路径的权值为\(s_u\opluss_v\)。现在转变为......
  • 重链剖分的另一个性质
    我们大家都知道树的节点深度和是比树的节点高度和要大的,这个直观感受一下就能理解。什么时候这俩东西一样呢?答案是树形态形如一条链的时候。回忆重链剖分,重链剖分的一个性质是如果说我们把所有重链缩成一个点,形成的新树上节点深度最大是\(\logn\)级别,当然用完全二叉树就能把深......