洛谷题单入门4-P1047 [NOIP 2005 普及组] 校门外的树-python

输入格式
第一行有两个整数,分别表示马路的长度 l 和区域的数目 m。

接下来 m 行,每行两个整数 u,v,表示一个区域的起始点和终止点的坐标。

输出格式
输出一行一个整数,表示将这些树都移走后,马路上剩余的树木数量。
说明/提示

区间的合并

class Solution:
    @staticmethod
    def oi_input():
        """从标准输入读取数据"""
        l, m = map(int, input().split())
        intervals = [tuple(map(int, input().split())) for _ in range(m)]
        return l, m, intervals

    @staticmethod
    def oi_test():
        """提供测试数据"""
        l, m = 500, 3
        intervals = [(150, 300), (100, 200), (470, 471)]
        return l, m, intervals

    @staticmethod
    def solution(l, m, intervals):
        """合并区间并计算剩余树数"""
        intervals.sort()
        merged = []
        for u, v in intervals:
            if merged and merged[-1][1] >= u:
                merged[-1] = (merged[-1][0], max(merged[-1][1], v))
            else:
                merged.append((u, v))
        total_removed = sum(v - u + 1 for u, v in merged)
        print((l + 1) - total_removed)


oi_input = Solution.oi_input
oi_test = Solution.oi_test
solution = Solution.solution

if __name__ == '__main__':
    # l, m, intervals = oi_test()
    l, m, intervals = oi_input()
    solution(l, m, intervals)

线段树

class Solution:
    @staticmethod
    def oi_input():
        """从标准输入读取数据"""
        l, m = map(int, input().split())
        intervals = [tuple(map(int, input().split())) for _ in range(m)]
        return l, m, intervals

    @staticmethod
    def oi_test():
        """提供测试数据"""
        l, m = 500, 3
        intervals = [(150, 300), (100, 200), (470, 471)]
        return l, m, intervals

    @staticmethod
    def solution(l, m, intervals):
        """线段树实现区间覆盖"""

        class SegmentTree:
            def __init__(self, L):
                self.n = L
                self.size = 1
                # 扩展为2的幂
                while self.size < self.n + 1:
                    self.size <<= 1

                # 初始化数据结构
                self.tree = [0] * (2 * self.size)
                self.lazy = [False] * (2 * self.size)

                # 初始化叶子节点
                for i in range(self.size):
                    self.tree[self.size + i] = 1 if i <= self.n else 0

                # 构建线段树
                for i in range(self.size - 1, 0, -1):
                    self.tree[i] = self.tree[2 * i] + self.tree[2 * i + 1]

            def _apply(self, node, l, r):
                """节点覆盖操作"""
                self.tree[node] = 0
                if node < self.size:
                    self.lazy[node] = True

            def _push(self, node, l, r):
                """下传懒标记"""
                if self.lazy[node]:
                    mid = (l + r) // 2
                    self._apply(2 * node, l, mid)
                    self._apply(2 * node + 1, mid + 1, r)
                    self.lazy[node] = False

            def range_cover(self, a, b):
                """区间覆盖入口"""

                def update(node, l, r):
                    if a > r or b < l: return
                    if a <= l and r <= b:
                        self._apply(node, l, r)
                        return
                    self._push(node, l, r)
                    mid = (l + r) // 2
                    update(2 * node, l, mid)
                    update(2 * node + 1, mid + 1, r)
                    self.tree[node] = self.tree[2 * node] + self.tree[2 * node + 1]

                update(1, 0, self.size - 1)

            def query_total(self):
                """查询剩余树数"""
                return self.tree[1]

        # 执行线段树操作
        st = SegmentTree(l)
        for u, v in intervals:
            st.range_cover(u, v)
        print(st.query_total())



oi_input = Solution.oi_input
oi_test = Solution.oi_test
solution = Solution.solution

if __name__ == '__main__':
    # 使用测试数据
    l, m, intervals = oi_test()

    # 使用标准输入
    # l, m, intervals = oi_input()

    # 运行解决方案
    solution(l, m, intervals)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值