2022蓝桥杯省赛·最长不下降子序列·线段树Python实现

代码如下: 

n, k = map(int, input().split())
nums = list(map(int, input().split()))
dpl, dpr = [0] * (n + 1), [0] * (n + 1)


# 子节点信息传递到父节点
def pushUp(root):
    tree[root] = max(tree[2 * root], tree[2 * root + 1])


# 更新最大值
def update(L, val, tleft, tright, root):
    if tleft == tright:
        tree[root] = max(tree[root], val)
        return
    mid = (tleft + tright) // 2
    if L <= mid:
        update(L, val, tleft, mid, 2 * root)
    else:
        update(L, val, mid + 1, tright, 2 * root + 1)
    pushUp(root)


# 查询最大值
def query(L, R, tleft, tright, root):
    if R < tleft or L > tright:
        return 0
    if L <= tleft and R >= tright:
        return tree[root]
    mid = (tleft + tright) // 2
    ans = 0
    if L <= mid:
        ans = max(ans, query(L, R, tleft, mid, 2 * root))
    if R > mid:
        ans = max(ans, query(L, R, mid + 1, tright, 2 * root + 1))
    return ans


# 离散化
uniques = set(nums)
rank_map = {v: i + 1 for i, v in enumerate(sorted(uniques))}

m = len(rank_map)
tree = [0] * (4 * len(rank_map))

ans = k

# 维护出从左到右 i 位置的最长不下降子序列
for i in range(n):
    rank = rank_map[nums[i]]
    val = query(1, rank, 1, m, 1)
    update(rank, val + 1, 1, m, 1)
    dpl[i] = val + 1
    ans = max(ans, dpl[i])

tree = [0] * (4 * len(rank_map))
# 同样维护从右到左 i 位置的最长不上升子序列
for i in range(n - 1, -1, -1):
    rank = rank_map[nums[i]]
    val = query(rank, m, 1, m, 1)
    update(rank, val + 1, 1, m, 1)
    dpr[i] = val + 1
    ans = max(ans, dpr[i])

    # 这里维护的同时要随时与 k 个数前的 dpl[be] 取 max
    be = i - k - 1;
    if be >= 0:
        tt = rank_map[nums[be]];
        ans = max(ans, dpl[be] + k + query(tt, m, 1, m, 1));
    # 在比 nums[be] 大的区间中找 max 值,这样才能保证没有遗漏,因为中间可能不止空出 k 个数

# 最后考虑一段最长不下降子序列+k个数的情况
for i in range(n - k):
    ans = max(ans, dpl[i] + k);
for i in range(n - 1, k - 1, -1):
    ans = max(ans, dpr[i] + k);

print(ans)

 参考的文章:

​​​​​​​​​​​​​​『 一题三解 』 贪心+二分搜索、树状数组、线段树 - 最长递增子序列 - 力扣(LeetCode)

(65条消息) [蓝桥杯2022初赛A组] 最长不下降子序列(dp + 权值线段树)_阐上的博客-CSDN博客

线段树有关:https://fanfansann.blog.csdn.net/article/details/104274713

用了两天的空闲时间研究这道当时没做出的题,从最开始的动态规划,到树状数组,再到最后的线段树,解题的过程也是学习的过程。在此记录,希望之后继续巩固。

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Eureka!!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值