线段树_P3372/P3373_Python

前面是线段树的模版代码,后面有例题P3372和P3373的应用 

话不多说,上代码

class Node:                 # 节点类
    def __init__(self, l, r):
        self.l = l          # 区间左端点
        self.r = r          # 区间右端点
        self.left = None    # 左子节点
        self.right = None   # 右子节点
        self.sum = 0        # 区间和
        self.max = -float('inf')  # 区间最大值
        self.min = float('inf')   # 区间最小值
        self.mul = 1       # 乘法延迟标记(初始为1)
        self.add = 0       # 加法延迟标记(初始为0)
        
class Tree:
    '''
    构造及更新部分
    '''
    def __init__(self, data, mod):  # 增加mod参数
        self.n = len(data)
        self.mod = mod      # 存储模数
        self.root = self._build(0, self.n - 1, data)
    
    def _build(self, l, r, data):
        """构建线段树"""
        node = Node(l, r)
        if l == r:  # 叶子节点
            node.sum = data[l] % self.mod  # 初始值取模
            node.max = data[l] % self.mod
            node.min = data[l] % self.mod
            return node
        mid = (l + r) // 2
        node.left = self._build(l, mid, data)
        node.right = self._build(mid+1, r, data)
        node.sum = (node.left.sum + node.right.sum) % self.mod
        node.max = max(node.left.max, node.right.max)
        node.min = min(node.left.min, node.right.min)
        return node
    
    def _push_down(self, node):
        """下推懒惰延迟更新标记"""
        # 先处理乘法,再处理加法
        if node.mul != 1 or node.add != 0:
            left = node.left
            right = node.right
            
            # 更新左子树
            if node.mul != 1:
                left.sum = (left.sum * node.mul) % self.mod
                left.max = (left.max * node.mul) % self.mod
                left.min = (left.min * node.mul) % self.mod
                left.mul = (left.mul * node.mul) % self.mod
                left.add = (left.add * node.mul) % self.mod
                
            if node.add != 0:
                left.sum = (left.sum + node.add * (left.r - left.l + 1)) % self.mod
                left.max = (left.max + node.add) % self.mod
                left.min = (left.min + node.add) % self.mod
                left.add = (left.add + node.add) % self.mod
            
            # 更新右子树
            if node.mul != 1:
                right.sum = (right.sum * node.mul) % self.mod
                right.max = (right.max * node.mul) % self.mod
                right.min = (right.min * node.mul) % self.mod
                right.mul = (right.mul * node.mul) % self.mod
                right.add = (right.add * node.mul) % self.mod
                
            if node.add != 0:
                right.sum = (right.sum + node.add * (right.r - right.l + 1)) % self.mod
                right.max = (right.max + node.add) % self.mod
                right.min = (right.min + node.add) % self.mod
                right.add = (right.add + node.add) % self.mod
            
            # 清除标记
            node.mul = 1
            node.add = 0
    
    def update_mul(self, L, R, k):
        """区间乘法更新:[L, R] 乘以 k"""
        self._update_mul(self.root, L, R, k % self.mod)  # 参数取模
    
    def _update_mul(self, node, L, R, k):
        if node.r < L or node.l > R:
            return
        if L <= node.l and node.r <= R:
            # 更新当前节点
            node.sum = (node.sum * k) % self.mod
            node.max = (node.max * k) % self.mod
            node.min = (node.min * k) % self.mod
            node.mul = (node.mul * k) % self.mod
            node.add = (node.add * k) % self.mod  # 加法标记也需要乘k
            return
        self._push_down(node)
        self._update_mul(node.left, L, R, k)
        self._update_mul(node.right, L, R, k)
        node.sum = (node.left.sum + node.right.sum) % self.mod
        node.max = max(node.left.max, node.right.max)
        node.min = min(node.left.min, node.right.min)
    
    def update_add(self, L, R, val):
        """区间加法更新:[L, R] 加上 val"""
        self._update_add(self.root, L, R, val % self.mod)  # 参数取模
    
    def _update_add(self, node, L, R, val):
        if node.r < L or node.l > R:
            return
        if L <= node.l and node.r <= R:
            node.sum = (node.sum + val * (node.r - node.l + 1)) % self.mod
            node.max = (node.max + val) % self.mod
            node.min = (node.min + val) % self.mod
            node.add = (node.add + val) % self.mod
            return
        self._push_down(node)
        self._update_add(node.left, L, R, val)
        self._update_add(node.right, L, R, val)
        node.sum = (node.left.sum + node.right.sum) % self.mod
        node.max = max(node.left.max, node.right.max)
        node.min = min(node.left.min, node.right.min)


    '''
    下面是查询部分
    '''
    def query_sum(self, L, R):
        """区间和查询"""
        return self._query_sum(self.root, L, R) % self.mod  # 结果取模
    
    def _query_sum(self, node, L, R):
        if node.r < L or node.l > R:
            return 0
        if L <= node.l and node.r <= R:
            return node.sum
        self._push_down(node)
        return (self._query_sum(node.left, L, R) + self._query_sum(node.right, L, R)) % self.mod
    
    def query_max(self, L, R):
        """区间最大值查询"""
        return self._query_max(self.root, L, R) % self.mod
    
    def _query_max(self, node, L, R):
        if node.r < L or node.l > R:
            return -float('inf')
        if L <= node.l and node.r <= R:
            return node.max
        self._push_down(node)
        return max(self._query_max(node.left, L, R), self._query_max(node.right, L, R))
    
    def query_min(self, L, R):      # 有点像最小堆
        """区间最小值查询"""
        return self._query_min(self.root, L, R) % self.mod
    
    def _query_min(self, node, L, R):
        if node.r < L or node.l > R:
            return float('inf')
        if L <= node.l and node.r <= R:
            return node.min
        self._push_down(node)
        return min(self._query_min(node.left, L, R), self._query_min(node.right, L, R))


'''
P3372应用
'''
n, m = map(int, input().split())
a = list(map(int, input().split()))
st = Tree(a, float('inf'))
for _ in range(m):
    parts = input().split()
    if parts[0] == '1':
        L = int(parts[1])
        R = int(parts[2])
        val = int(parts[3])
        st.update_add(L-1, R-1, val)
    else:
        L = int(parts[1])
        R = int(parts[2])
        print(int(st.query_sum(L-1, R-1)))


'''
P3373应用
'''
n, m, q = map(int, input().split())
a = list(map(int, input().split()))
st = Tree(a, q)  # 传入模数参数
for _ in range(m):
    parts = input().split()
    if parts[0] == '1':
        L = int(parts[1]) - 1  # 转0-based
        R = int(parts[2]) - 1
        val = int(parts[3])
        st.update_mul(L, R, val)
    elif parts[0] == '2':
        L = int(parts[1]) - 1
        R = int(parts[2]) - 1
        val = int(parts[3])
        st.update_add(L, R, val)
    else:
        L = int(parts[1]) - 1
        R = int(parts[2]) - 1
        print(st.query_sum(L, R))

### 解决洛谷 P1047 校门外的树 对于洛谷 P1047 校门外的树问题,核心思路在于处理线段上的种植与移除操作。通过维护一个数据结构来高效管理这些变化,可以显著提高算法效率。 #### 数据结构的选择 为了有效管理和查询区间内的状态变更,可以选择使用差分数组或线段树等高级数据结构。然而,在此题中更推荐采用一种简化的方法——利用布尔数组记录每棵树的状态[^1]。 #### 算法描述 定义两个主要过程: - **初始化**:创建一个长度为 `L` 的布尔数组 `tree[]` 来表示校门到家之间的路段上是否有树。 - **更新操作**:针对每次修改请求(种树/砍伐),只需遍历指定范围并相应调整该范围内各位置处的标志位即可完成一次完整的更改动作;最后统计剩余树木总数作为输出结果的一部分返回给调用者。 下面是具体的 Python 实现方式: ```python def solve(n, m, operations): L = n + 1 # 路径总长加一以适应索引从零开始的情况 tree = [False] * (L) # 初始化路径,默认无任何植物存在 for op_type, start_pos, end_pos in operations: if op_type == 1: # 种植新苗 for i in range(start_pos, min(end_pos+1,L)): tree[i] = True elif op_type == 2: # 清理现有植被 for i in range(max(1,start_pos),min(end_pos+1,L)): tree[i] = False count_trees = sum(tree[1:]) # 统计实际存在的树木数量 return count_trees if __name__ == "__main__": import sys input_data = list(map(int,sys.stdin.read().strip().split())) idx=0 N,M=input_data[idx],input_data[idx+1];idx+=2; ops=[tuple(input_data[i:i+3])for i in range(idx,len(input_data),3)] result=solve(N,M,ops) print(result) ``` 上述代码实现了对输入指令集的操作解析以及最终答案计算的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值