博客
关于我
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/

    你可能感兴趣的文章
    PHP学习总结(5)——PHP入门篇之PHP字符串
    查看>>
    PHP学习总结(7)——PHP入门篇之PHP注释
    查看>>
    rabbitmq重启失败
    查看>>
    PHP学习总结(9)——PHP入门篇之WAMPServer服务控制面板介绍
    查看>>
    php学习笔记---php调试和开发工具整理
    查看>>
    PHP学习笔记一:谁动了你的mail(),PHP?
    查看>>
    PHP安全实战
    查看>>
    php安装扩展
    查看>>
    php实现上传(多个)文件函数封装
    查看>>
    php实现下载文件方法
    查看>>
    php实现单链表
    查看>>
    php实现图片背景换色功能
    查看>>
    php实现多个一维数组对应合并成二维数组
    查看>>
    php实现多关键字查找方法
    查看>>
    PHP实现微信公众号H5支付
    查看>>
    PHP实现微信公众号网页授权
    查看>>
    PHP实现微信小程序推送消息至公众号
    查看>>
    php实现根据身份证获取年龄
    查看>>
    PHP实现的MongoDB数据增删改查
    查看>>
    php实现短信验证功能
    查看>>