分析

思路很简单
遍历每个作为最大值,然后区间不包含当前最大值的都可以减掉
easy version就可以这样暴力解决
然后求出最大差值

暴力解法

import sys
input = sys.stdin.readlinen, m = list(map(int, input().split()))
a = list(map(int, input().split()))
intervals = []
for _ in range(m):l, r = n, m = list(map(int, input().split()))intervals.append([l, r])if m == 0:print(max(a) - min(a))print(0)print()
else:# fix maxmaxdiff = -0xffffffffchooseNum = 0chooseIdxs = []for maxIdx, maxn in enumerate(a):tmpNum = 0tmpIdxs = []tmp_a = a[:]cnt = 0for l, r in intervals:cnt += 1if l - 1 <= maxIdx <= r - 1:continuefor i in range(l, r + 1):tmp_a[i - 1] -= 1tmpNum += 1tmpIdxs.append(cnt)if maxn - min(tmp_a) > maxdiff:maxdiff = maxn - min(tmp_a)chooseNum = tmpNumchooseIdxs = tmpIdxsprint(maxdiff)print(chooseNum)print(*chooseIdxs)

优化

如果n和m变大
这个方法就失效了
我们要用线段树进行区间修改
特别地,我们考虑全部都选择
然后遍历maxn节点(从左到右)
以它i为左端点的所有区间都可以加上(不选择)
然后所以i - 1(当前为i)为右区间的都可以删掉
对于那种横跨i的即l <= i = r的不用删
这样的算法有一个好处就是可以保证当前包含i的所有区间都没有选择
然后线段树查询即可

segTree solution

import sys
from functools import reduce
from collections import defaultdict
input = sys.stdin.readlineclass SegTree:'''支持增量更新,覆盖更新,序列更新,任意RMQ操作基于二叉树实现初始化:O(1)增量更新或覆盖更新的单次操作复杂度:O(log k)序列更新的单次复杂度:O(n)'''def __init__(self, f1, f2, l, r, v=0):'''初始化线段树[left,right)f1,f2示例:线段和:f1=lambda a,b:a+bf2=lambda a,n:a*n线段最大值:f1=lambda a,b:max(a,b)f2=lambda a,n:a线段最小值:f1=lambda a,b:min(a,b)f2=lambda a,n:a'''self.ans = f2(v, r - l)self.f1 = f1self.f2 = f2self.l = l  # leftself.r = r  # rightself.v = v  # init valueself.lazy_tag = 0  # Lazy tagself.left = None  # SubTree(left,bottom)self.right = None  # SubTree(right,bottom)@propertydef mid_h(self):return (self.l + self.r) // 2def create_subtrees(self):midh = self.mid_hif not self.left and midh > self.l:self.left = SegTree(self.f1, self.f2, self.l, midh)if not self.right:self.right = SegTree(self.f1, self.f2, midh, self.r)def init_seg(self, M):'''将线段树的值初始化为矩阵Matrx输入保证Matrx与线段大小一致'''m0 = M[0]self.lazy_tag = 0for a in M:if a != m0:breakelse:self.v = m0self.ans = self.f2(m0, len(M))return self.ansself.v = '#'midh = self.mid_hself.create_subtrees()self.ans = self.f1(self.left.init_seg(M[:midh - self.l]), self.right.init_seg(M[midh - self.l:]))return self.ansdef cover_seg(self, l, r, v):'''将线段[left,right)覆盖为val'''if self.v == v or l >= self.r or r <= self.l:return self.ansif l <= self.l and r >= self.r:self.v = vself.lazy_tag = 0self.ans = self.f2(v, self.r - self.l)return self.ansself.create_subtrees()if self.v != '#':if self.left:self.left.v = self.vself.left.ans = self.f2(self.v, self.left.r - self.left.l)if self.right:self.right.v = self.vself.right.ans = self.f2(self.v, self.right.r - self.right.l)self.v = '#'# push upself.ans = self.f1(self.left.cover_seg(l, r, v), self.right.cover_seg(l, r, v))return self.ansdef inc_seg(self, l, r, v):'''将线段[left,right)增加val'''if v == 0 or l >= self.r or r <= self.l:return self.ans# self.ans = '?'if l <= self.l and r >= self.r:if self.v == '#':self.lazy_tag += velse:self.v += vself.ans += self.f2(v, self.r - self.l)return self.ansself.create_subtrees()if self.v != '#':self.left.v = self.vself.left.ans = self.f2(self.v, self.left.r - self.left.l)self.right.v = self.vself.right.ans = self.f2(self.v, self.right.r - self.right.l)self.v = '#'self.pushdown()self.ans = self.f1(self.left.inc_seg(l, r, v), self.right.inc_seg(l, r, v))return self.ansdef inc_idx(self, idx, v):'''increase idx by val'''if v == 0 or idx >= self.r or idx < self.l:return self.ansif idx == self.l == self.r - 1:self.v += vself.ans += self.f2(v, 1)return self.ansself.create_subtrees()if self.v != '#':self.left.v = self.vself.left.ans = self.f2(self.v, self.left.r - self.left.l)self.right.v = self.vself.right.ans = self.f2(self.v, self.right.r - self.right.l)self.v = '#'self.pushdown()self.ans = self.f1(self.left.inc_idx(idx, v), self.right.inc_idx(idx, v))return self.ansdef pushdown(self):if self.lazy_tag != 0:if self.left:if self.left.v != '#':self.left.v += self.lazy_tagself.left.lazy_tag = 0else:self.left.lazy_tag += self.lazy_tagself.left.ans += self.f2(self.lazy_tag, self.left.r - self.left.l)if self.right:if self.right.v != '#':self.right.v += self.lazy_tagself.right.lazy_tag = 0else:self.right.lazy_tag += self.lazy_tagself.right.ans += self.f2(self.lazy_tag, self.right.r - self.right.l)self.lazy_tag = 0def query(self, l, r):'''查询线段[right,bottom)的RMQ'''if l >= r: return 0if l <= self.l and r >= self.r:return self.ansif self.v != '#':return self.f2(self.v, min(self.r, r) - max(self.l, l))midh = self.mid_hanss = []if l < midh:anss.append(self.left.query(l, r))if r > midh:anss.append(self.right.query(l, r))return reduce(self.f1, anss)n, m = list(map(int, input().split()))
a = list(map(int, input().split()))
ls = defaultdict(list)
intervals = []
for _ in range(m):l, r = list(map(int, input().split()))intervals.append([l, r])# fix l, get many rls[l - 1].append(r - 1)if m == 0:print(max(a) - min(a))print(0)print()
else:# fix max# use segTreesf1 = lambda a, b: min(a, b)f2 = lambda a, n: asegtree = SegTree(f1, f2, 0, n, 0)# initfor i in range(n):segtree.inc_idx(i, a[i])# delete all intervals# if we later fix a maxn, we can add corresponding intervalsfor l, r in intervals:segtree.inc_seg(l - 1, r, -1)maxD, maxI = 0, 1rs = defaultdict(list)for i in range(n):# fix ifor r in ls[i]:# add intervals back(not choose)segtree.inc_seg(i, r + 1, 1)rs[r].append(i)# delete useless intervals again# means that we choose these intervalsfor l in rs[i - 1]:segtree.inc_seg(l, i, -1)# find now dd = a[i] - segtree.query(0, n)if d > maxD:maxD, maxI = d, iids = []for i, interval in enumerate(intervals):if interval[1] - 1 < maxI or interval[0] - 1 > maxI: # outsideids.append(i + 1)print(maxD)print(len(ids))print(*ids)

总结

线段树 + 全删逆向 + 剔除包含当前节点的所有区间的ls + rs算法

codeforces:E2. Array and Segments (Hard version)【线段树 + 区间修改】相关推荐

  1. 【模板】线段树区间修改

    区间修改: 区间修改过程类似于区间询问,例如将[ul, ur]内的所有元素都加上v,则进行如下操作: 当当前区间被区间[ul, ur]所包含时, 当前的节点值加上区间长度(r - l  + 1)乘以v ...

  2. python:线段树区间修改 + 区间查询 模板 + 坑点总结

    from functools import reduceclass SegTree:'''支持增量更新,覆盖更新,序列更新,任意RMQ操作基于二叉树实现初始化:O(1)增量更新或覆盖更新的单次操作复杂 ...

  3. UVa 11992 (线段树 区间修改) Fast Matrix Operations

    比较综合的一道题目. 二维的线段树,支持区间的add和set操作,然后询问子矩阵的sum,min,max 写完这道题也是醉醉哒,代码仓库里还有一份代码就是在query的过程中也pushdown向下传递 ...

  4. 【UOJ 53】线段树区间修改

    [题目描述]: 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 [输入描述]: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

  5. POJ 2777 Count Color (线段树区间修改 + 状态压缩)

    题目链接:POJ 2777 Count Color [题目大意] 给你 n 块板子, 编号1--n , 板子的颜色最多30种, 初始时  板子的颜色都是 1: 有两种操作 1 .把给定区间的板子染成一 ...

  6. HDU 1698 Just a Hook (线段树区间修改+区间查询)

    题目链接: 传送门 题意:Pudge对装备钩子进行若干次的强化,强化分为三种分别对应的价值是1,2,3,在经历过若干次操作后,输出钩子对应的总价值,每次强化都是对钩子进行区间修改 解题思路:在明白了题 ...

  7. hdu1698(线段树/区间修改/求和)

    hdu1698"Just a Hook" 题意: 有一个区间s [1,n],每一节si的初始价值为1.定义操作:x y val,将区间[x,y]中的每一个小节的价值改为val.问: ...

  8. 1631 小鲨鱼在51nod小学(线段树区间修改+单点查询:不用下传lazy的区间修改)

    题目描述: 1631 小鲨鱼在51nod小学 鲨鱼巨巨2.0(以下简称小鲨鱼)以优异的成绩考入了51nod小学.并依靠算法方面的特长,在班里担任了许多职务. 每一个职务都有一个起始时间A和结束时间B, ...

  9. tzoj3315 买火车票(线段树+区间修改+区间查询)

    时间限制(普通/Java):1000MS/3000MS     内存限制:65536KByte 描述 Byteotian州铁道部决定赶上时代,为此他们引进了城市联网.假设城市联网顺次连接着n 个市从1 ...

最新文章

  1. 快排递归非递归python_Python递归神经网络终极指南
  2. Ubuntu默认密码,及其修改
  3. lua 调用文件中的函数调用_四、C++获得Lua的变量和Table的值
  4. 中国高压断路器(QF)行业发展战略及创新前景展望报告2022-2028年版
  5. 计算机网络——数据链路层的概述
  6. 分块编码(Transfer-Encoding: chunked)VS Content-length
  7. MYSQL GROUP BY 对多个字段进行分组
  8. 强大实用的DISM命令
  9. (转)Django ==== 实战学习篇九 在session中保存购物车
  10. 05:年龄与疾病【一维数组】
  11. 中国特夫行业市场供需与战略研究报告
  12. Linux 下查看sqlite文件
  13. java litjson_.NET平台开源JSON库LitJSON的使用方法
  14. Mac系统, 切换大小写失灵
  15. PVID和VID的理解
  16. Acwing-872. 最大公约数
  17. 代码坏的味道13:夸夸其谈未来性(Speculative Generality)
  18. 阿里投资分众,大战在即的电梯广告市场却有本糊涂账?
  19. 【若依vue框架学习】3.通过Excel导入数据/通过反射读取注解
  20. 2022最新酒桌小游戏小程序源码(附带流量主)

热门文章

  1. 小波变换(分解/重构)和彩色图像分量处理
  2. win10系统中Bitlocker提示等待激活解决办法
  3. 苹果手机来电防火墙_苹果手机怎么来电录音电话通话
  4. PyTorch 入门实战(四)——利用Torch.nn构建卷积神经网络
  5. qt 正则 html,QT之http网络访问和正则表达式 2020-10-31
  6. JS获取url参数 返回一个对象
  7. HiBench 7.x 使用问题整理
  8. 利用SVM分类器批量分类图片颜色信息
  9. Java开发之百度地图2 :计算两地之间的距离
  10. mysql 签到 存储,MySQL和Redis实现用户签到,你喜欢怎么实现?