博客
关于我
P3384 树链剖分 (点权,模板)
阅读量:228 次
发布时间:2019-03-01

本文共 4544 字,大约阅读时间需要 15 分钟。

为了解决这个问题,我们需要处理一棵树上的四种操作,每个操作都会对路径上的节点值进行加法或求和。为了高效处理这些操作,我们可以使用深度优先搜索(DFS)预处理和线段树来支持区间操作。

方法思路

  • 预处理

    • 使用DFS确定每个节点的进入时间和退出时间,这样可以用区间来表示子树或路径。
    • 确定每个节点的父节点和子节点顺序,用于后续操作。
  • 线段树的构建

    • 基于预处理的序号信息,构建线段树来支持区间加法和求和操作。
    • 线段树的每个节点表示一个区间,用于快速处理路径上的操作。
  • 处理操作

    • 操作1:路径加法,分解路径为多个区间,分别进行加法。
    • 操作2:路径求和,分解路径为多个区间,分别求和。
    • 操作3:子树加法,确定子树对应的区间,进行加法。
    • 操作4:子树求和,确定子树对应的区间,求和。
    • 所有结果都对模数P取模后输出。
  • 解决代码

    import syssys.setrecursionlimit(1 << 25)MOD = 10**18 + 3def main():    import sys    input = sys.stdin.read    data = input().split()    idx = 0    N = int(data[idx]); idx +=1    M = int(data[idx]); idx +=1    root = int(data[idx]); idx +=1    P = int(data[idx]); idx +=1    v = list(map(int, data[idx:idx+N]))    idx += N    v = [0] + v  # 1-based    edges = [[] for _ in range(N+1)]    for _ in range(N-1):        x = int(data[idx]); idx +=1        y = int(data[idx]); idx +=1        edges[x].append(y)        edges[y].append(x)    from collections import deque    # 预处理,计算sz, fa, son, d, top, id, rk    sz = [0]*(N+1)    fa = [0]*(N+1)    son = [0]*(N+1)    d = [0]*(N+1)    top = [0]*(N+1)    id = [0]*(N+1)    rk = [0]*(N+1)    time = 0    visited = [False]*(N+1)    stack = [(root, -1)]    while stack:        x, parent = stack.pop()        if visited[x]:            continue        visited[x] = True        sz[x] = 1        for child in edges[x]:            if child != parent and not visited[child]:                fa[child] = x                son[x] = child                stack.append((child, x))        sz[x] = sum(sz[child] for child in edges[x] if child != parent and fa[child] == x)    # 预处理top, id, rk    top[root] = root    id[root] = 1    rk[1] = root    time = 2    stack = [(root, root)]    while stack:        x, p = stack.pop()        for child in edges[x]:            if child != p and fa[child] == x:                top[child] = top[x]                id[child] = time                rk[time] = child                time +=1                stack.append((child, x))    # 线段树构建    # 非动态开点,线段树大小为 2*2^h, 其中 h 是最小使得 2^h >= N    maxn = 2 * (1 << (20 if N > 100000 else 17))    a = [0]*(2*maxn)    for i in range(1, N+1):        a[id[i]] = v[i]    for i in range(maxn-1, 0, -1):        a[i] = (a[2*i] + a[2*i+1]) % P    def update(l, r, val, node):        if l == r:            a[node] = (a[node] + val * (r - l +1)) % P            return        mid = (l + r) //2        if l <= mid:            update(l, mid, val, 2*node)        if r > mid:            update(mid+1, r, val, 2*node+1)        a[node] = (a[2*node] + a[2*node+1]) % P    def query(l, r, node):        if l > r:            return 0        if l == r:            return a[node]        mid = (l + r) //2        res = 0        if l <= mid:            res += query(l, mid, 2*node)        if r > mid:            res += query(mid+1, r, 2*node+1)        return res % P    for _ in range(M):        parts = data[idx:idx+4]        if parts[0] == '1':            x = int(data[idx+1])            y = int(data[idx+2])            z = int(data[idx+3])            idx +=4            while top[x] != top[y]:                if d[top[x]] > d[top[y]]:                    x, y = y, x                start = id[top[x]]                end = id[x]                update(start, end, z, 1)                x = fa[top[x]]            if top[x] == top[y]:                x = y            start = id[x]            end = id[x]            update(start, end, z, 1)        elif parts[0] == '2':            x = int(data[idx+1])            y = int(data[idx+2])            idx +=3            res = 0            while top[x] != top[y]:                if d[top[x]] > d[top[y]]:                    x, y = y, x                start = id[top[x]]                end = id[x]                res += query(start, end, 1)                res %= P                x = fa[top[x]]            if top[x] == top[y]:                x = y            start = id[x]            end = id[x]            res += query(start, end, 1)            res %= P            print(res % P)        elif parts[0] == '3':            x = int(data[idx+1])            z = int(data[idx+2])            idx +=3            start = id[x]            end = rk[x]            update(start, end, z, 1)        elif parts[0] == '4':            x = int(data[idx+1])            idx +=2            start = id[x]            end = rk[x]            res = query(start, end, 1)            print(res % P)if __name__ == '__main__':    main()

    代码解释

  • 预处理阶段

    • 使用DFS计算每个节点的大小、父节点、子节点、深度、进入时间和退出时间等信息,用于区间表示。
  • 线段树构建

    • 基于预处理结果,构建线段树来支持区间加法和求和操作。
  • 操作处理

    • 对于每个操作,分解路径或子树区间,调用线段树进行相应操作,结果对模数取模后输出。
  • 这种方法确保了路径和子树操作的高效处理,适用于大规模数据。

    转载地址:http://cnzv.baihongyu.com/

    你可能感兴趣的文章
    NutUI:京东风格的轻量级 Vue 组件库
    查看>>
    NutzCodeInsight 2.0.7 发布,为 nutz-sqltpl 提供友好的 ide 支持
    查看>>
    NutzWk 5.1.5 发布,Java 微服务分布式开发框架
    查看>>
    NUUO网络视频录像机 css_parser.php 任意文件读取漏洞复现
    查看>>
    Nuxt Time 使用指南
    查看>>
    NuxtJS 接口转发详解:Nitro 的用法与注意事项
    查看>>
    NVelocity标签使用详解
    查看>>
    NVelocity标签设置缓存的解决方案
    查看>>
    Nvidia Cudatoolkit 与 Conda Cudatoolkit
    查看>>
    NVIDIA GPU 的状态信息输出,由 `nvidia-smi` 命令生成
    查看>>
    NVIDIA-cuda-cudnn下载地址
    查看>>
    nvidia-htop 使用教程
    查看>>
    nvidia-smi 参数详解
    查看>>
    Nvidia驱动失效,采用官方的方法重装更快
    查看>>
    nvmw安装node-v4.0.0之后版本的临时解决办法
    查看>>
    nvm切换node版本
    查看>>
    nvm安装以后,node -v npm 等命令提示不是内部或外部命令 node多版本控制管理 node多版本随意切换
    查看>>
    ny540 奇怪的排序 简单题
    查看>>
    NYOJ 1066 CO-PRIME(数论)
    查看>>
    nyoj------203三国志
    查看>>