区间最值操作与历史最值问题(一)

本文详细介绍了如何使用SegmentTree Beats维护区间取最值操作,包括区间最值操作、区间历史最值的维护,以及支持区间加减操作的方法。通过实例解析和代码展示,解释了如何在不同场景下应用这些技术,如GorgeousSequence和EPhoneNetwork等题目。文章还探讨了将数域进行划分以支持更多操作,如在最假女选手问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

本文主要讲解一种叫做 SegmentTree BeatsSegmentTree~BeatsSegmentTree Beats 的维护区间取最值操作的问题,以及维护区间历史最值的方法。本文参考自许多博客,以及吉老师 201620162016 年的集训队论文,会加上很多例题进行讲解QAQ

区间最值操作

例题一 [HDU5306] Gorgeous Sequence

给出长度为 n(n≤1e6)n (n\le 1e6)n(n1e6) 的序列 { An}\{A_n\}{ An}m(m≤1e6)m(m\le1e6)m(m1e6) 次操作,每次操作为以下三种类型之一:
1.给出 l,r,kl,r,kl,r,k,对所有 i∈[l,r]i\in[l,r]i[l,r],将 AiA_iAi 变成 min(Ai,k)min(A_i,k)min(Ai,k)
2.给出 l,rl,rl,r,询问序列 AAA 在区间 [l,r][l,r][l,r] 的最大值
3.给出 l,rl,rl,r,询问序列 AAA 在区间 [l,r][l,r][l,r] 的和

在这道题中,第一种操作就叫区间最值操作。
我们把这种操作看作是一种标记,那怎么快速更新区间的信息呢?
可以发现,由于存在不同的值,所以区间的信息是无法更新的。但是如果只有一种值,区间取 minminmin 就变得轻而易举了。
因此,可以想到一个看起来像暴力的做法。
我们用线段树维护每个区间的最大值 mxmxmx 和严格次大值 sesese,以及 mxmxmx 的个数 cntcntcnt
考虑 111 操作,对于一个线段树上的区间,我们分类讨论一下:

  • 如果 mx≤k:mx\leq k:mxk:
    那么我们可以直接 returnreturnreturn
  • 如果 mx>k,se<k:mx>k,se < k:mx>k,se<k:
    我们在区间打一个 tagtagtag 标记,并更新最大值为 kkk,同时更新 sum=sum−cnt∗(mx−k)sum = sum - cnt * (mx - k)sum=sumcnt(mxk)
  • 如果 se≥k:se\ge k:sek:
    因为此时我们并不知道哪些数大于 ttt,于是我们暴力递归子区间

这样子的操作看起来非常滴玄学,但是跑起来却非常滴快,轻松地就把这题 AAA 了。
吉老师通过势能分析得出这样子操作总的时间复杂度是 O(nlogn)O(nlogn)O(nlogn) 的。我们也可以换一种角度思考,假设会进行递归,那么一定存在一个节点,满足 mx>t,se>tmx>t,se>tmx>t,se>t,那么通过这次取 minminmin 之后,sesesemxmxmx 都会变成 kkk。也就是说,值域会减少一。而线段树有 lognlognlogn 层,每层的值域加起来是 O(n)O(n)O(n) 的,因此值域最多只有 O(nlogn)O(nlogn)O(nlogn),所以总的复杂度是 O((n+m)logn)O((n+m)logn)O((n+m)logn) 的(虽然看起来还是很玄学
为了方便理解,下面给出了这题区间打标记的代码:

void addtag(int rt, int c){
   
    if(mx[rt] <= c) return;
    sum[rt] -= cnt[rt] * (mx[rt] - c);
    mx[rt] = tag[rt] = c;//更新最大值并打标记
}
void pushdown(int rt){
   
    if(tag[rt]){
   
        addtag(lc, tag[rt]);
        addtag(rc, tag[rt]);
        tag[rt] = 0;
    }
}
void update(int l, int r, int rt, int a, int b, int c){
   
    if(mx[rt] <= c) return;
    if(l >= a && r <= b && se[rt] < c){
   //次大值小于 c,最大值大于 c,此时只修改最大值
        addtag(rt, c);
        return;
    }
    pushdown(rt);
    int m = l + r >> 1;
    if(a <= m) update(lson, a, b, c);
    if(b > m) update(rson, a, b, c);
    pushup(rt);
}
例题二 [2020ICPC小米邀请赛网络赛一] E Phone Network

给出长度为 nnn 的序列 { An}\{A_n\}{ An}mmm,满足 Ai∈[1,m]A_i\in [1,m]Ai[1,m](m≤n≤2e5)(m\le n\le 2e5)(mn2e5)
对于每个 k∈[1,m]k\in [1,m]k<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值