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

    你可能感兴趣的文章
    Objective-C实现cartesianProduct笛卡尔乘积算法(附完整源码)
    查看>>
    Objective-C实现check strong password检查密码强度算法(附完整源码)
    查看>>
    Objective-C实现chudnovsky algorithm楚德诺夫斯基算法(附完整源码)
    查看>>
    Objective-C实现CIC滤波器(附完整源码)
    查看>>
    Objective-C实现circle sort圆形排序算法(附完整源码)
    查看>>
    Objective-C实现CircularQueue循环队列算法(附完整源码)
    查看>>
    Objective-C实现clearBit清除位算法(附完整源码)
    查看>>
    Objective-C实现climbStairs爬楼梯问题算法(附完整源码)
    查看>>
    Objective-C实现cocktail shaker sort鸡尾酒排序算法(附完整源码)
    查看>>
    Objective-C实现cocktailShakerSort鸡尾酒排序算法(附完整源码)
    查看>>
    Objective-C实现CoinChange硬币兑换问题算法(附完整源码)
    查看>>
    Objective-C实现collatz sequence考拉兹序列算法(附完整源码)
    查看>>
    Objective-C实现Collatz 序列算法(附完整源码)
    查看>>
    Objective-C实现comb sort梳状排序算法(附完整源码)
    查看>>
    Objective-C实现combinationSum组合和算法(附完整源码)
    查看>>
    Objective-C实现combinations排列组合算法(附完整源码)
    查看>>
    Objective-C实现combine With Repetitions结合重复算法(附完整源码)
    查看>>
    Objective-C实现combine Without Repetitions不重复地结合算法(附完整源码)
    查看>>
    Objective-C实现conjugate gradient共轭梯度算法(附完整源码)
    查看>>
    Objective-C实现connected components连通分量算法(附完整源码)
    查看>>