跳到主要内容

P5068 我回来了

据说这是一道“很能展现线段树灵活性”的题目。

难度省选/NOI−
算法线段树
日期2025-07-16

(老师口头讲太快了我得记一下才能听懂。)

题意建模

所有随从的血量构成一个数列 H={hi}1pH=\{h_i\}_1^p (有 pp 个随从),在这里我们假设数列是升序排列的(单调不减)。操作 1 就是在 HH 里插入新的元素。

操作2 的解释:从一个区间 [L,R][L,R] 中等概率地选择一个 dd(注意 L,R,dZL,R,d\in\mathbb{Z})我们也可以这样看:

D={di}={L,L+1,...,R1,R}.D=\{d_i\}=\{L,L+1,...,R-1,R\}.

f(di)=kf(d_i)=k 表示:最小的伤害次数 kZk\in\mathbb{Z},使得对所有随从,每次造成 did_i 点伤害,第 kk 次伤害时恰好没有随从死亡。所以:

E=diDf(di)RL+1.E=\frac{\sum_{d_i\in D}{f(d_i)}}{R-L+1}.

(注意 DD 的大小就是 RL+1R-L+1

说人话就是在(dd 的取值区间) [L,R][L,R] 上求 f(di)f(d_i) 的平均数。

但是呢,题目让我们输出 (RL+1)E(R-L+1)E,所以我们要求的是:

Ans=diDf(di)=j=LRf(j).\text{Ans}=\sum_{d_i\in D}{f(d_i)}=\sum_{j=L}^R{f(j)}.

说人话就是在 [L,R][L,R] 上对 f(di)f(d_i) 求和。

思路 #1

我们对一个单独的 dd 分析,f(d)f(d) 是什么意思。
假设 d=5d=5HH 如下:

H={1,2,3,4,5,  6,7,8,9,10,  11,12,13,14,15,  }.H=\{1,2,3,4,5,\space\space 6,7,8,9,10,\space\space11,12,13,14,15,\space\space \dots\}.

公式是有点丑,但是看得出来,前 5 个随从第 1 次就死了,再 5 个随从第 2 次就死了,等等。

这就是说(对于任意 dd):

H={1d,  d+12d,  2d+13d,  }.H=\{1\dots d,\space\space d+1\dots2d,\space\space 2d+1\dots3d,\space\space\dots\}.

我们发现 HH 被分为了若干组,第 ii 组随从会在第 ii 次伤害中死去。

实际的数据中,不一定每组都会存在,每组不一定个数相同,HH 也不一定从 11 开始,但是这里先不纠结这个细节。

还记得 f(d)f(d) 的定义么?最小的伤害次数 kk,使得第 kk 次伤害时没有随从死亡。那么,如果第 kk 次伤害时没有随从死亡,只有一种情况:

  • kk 组随从不存在。

又可以细分两种情况:

  1. 随从的数列中间空了一组。
  2. 所有随从都死了。

考虑,对于一个固定的 HH,如果此时的 dd 满足情况 2,f(d)f(d) 将取得最大值。也就是说:

f(d)pd.f(d)\leq \frac{p}{d}.

前提似乎是每个随从的血量互不相同?

不过老师就是这样写的。

所以:

Ans=j=LRf(j)j=LRpjp(lnRlnL).\text{Ans}=\sum_{j=L}^R{f(j)}\leq\sum_{j=L}^R\frac{p}{j}\approx p(\ln R-\ln L).

也就是说伤害次数在 O(nlogn)O(n\log n) 级别。

思路 #2

好的,让我们重新捋一下题目吧。现在问题被我们转化为了:

  1. 我们每次要处理询问,求区间 [L,R][L,R]f(j)f(j)。(操作 2)
  2. 而的计算 f(j)f(j)HH 有关,每次对 HH 修改的时候(操作 1)我们都要维护 f(j)f(j)

诶,维护区间和?不管那么多了,上线段树吧!

再看看题目:

1n1051\leq n\leq 10^51LRn1\leq L\leq R\leq n

很好啊,那我们就在 [1,n][1,n] 上建立一棵线段树 tree[ ]tree[\space]tree[j]tree[j] 就维护 f(j)f(j) 的值。操作 2 我们一个 getsum()\text{getsum}() 就可以 O(logn)O(\log n) 解决。