P6242 【模板】线段树 3

题目链接

P6242 【模板】线段树 3

【模板】线段树 3

题目背景

本题是线段树维护区间最值操作与区间历史最值的模板。

题目描述

给出一个长度为 n 的数列 A,同时定义一个辅助数组 BB 开始与 A 完全相同。接下来进行了 m 次操作,操作有五种类型,按以下格式给出:

  • 1 l r k:对于所有的 i[l,r],将 Ai 加上 kk 可以为负数)。
  • 2 l r v:对于所有的 i[l,r],将 Ai 变成 min(Ai,v)
  • 3 l r:求 i=lrAi
  • 4 l r:对于所有的 i[l,r],求 Ai 的最大值。
  • 5 l r:对于所有的 i[l,r],求 Bi 的最大值。

在每一次操作后,我们都进行一次更新,让 Bimax(Bi,Ai)

输入格式

第一行包含两个正整数 n,m,分别表示数列 A 的长度和操作次数。

第二行包含 n 个整数 A1,A2,,An,表示数列 A

接下来 m 行,每行行首有一个整数 op,表示操作类型;接下来两个或三个整数表示操作参数,格式见【题目描述】。

输出格式

对于 op{3,4,5} 的操作,输出一行包含一个整数,表示这个询问的答案。

样例 #1

样例输入 #1

5 6 1 2 3 4 5 3 2 5 1 1 3 3 4 2 4 2 3 4 1 5 1 5 3 1 4

样例输出 #1

14 6 6 11

提示

样例说明 #1

操作次数 输入内容 操作 数列 输出结果
0 1,2,3,4,5
1 3 2 5 求出 [2,5] 所有数的和 1,2,3,4,5 14
2 1 1 3 3 [1,3] 内所有数加 3 4,5,6,4,5
3 4 2 4 求出 [2,4] 所有数的最大值 4,5,6,4,5 6
4 2 3 4 1 [3,4] 所有数与 1 取最小值 4,5,1,1,5
5 5 1 5 求出 [1,5] 所有位置历史最大值的最大值 4,5,1,1,5 6
6 3 1 4 求出 [1,4] 所有数的和 4,5,1,1,5 11

数据规模与约定

  • 对于测试点 1,2,满足 n,m5000
  • 对于测试点 3,4,满足 op{1,2,3,4}
  • 对于测试点 5,6,满足 op{1,3,4,5}
  • 对于全部测试数据,保证 1n,m5×1055×108Ai5×108op[1,5]1lrn2000k20005×108v5×108

提示

本题输入量较大,请使用合理高效的读入方法。

解题思路

吉司机线段树

难点主要在于区间取 min 和区间查询历史最值:
区间取 min 可将区间整个值分为最大值和非最大值部分,设置最大值 mxa 和其次数 cnt 以及次大值 lmxa,如果区间取 min 的值 v 范围为 lmxa<v<mxa 则可将最大值 mxa 更新为 v,如果当前区间的 mxav 则整个区间不用更新,否则如果 lmxav 的话递归到其子树上
对于区间查询历史最值,将区间分为最大值和非最大值后,设置 4 个懒标记:mxaddnmxaddmxmxnmxmx,分别表示最大值、非最大值、最大值的最大值、非最大值的最大值的添加懒标记,后面两个懒标记主要用来处理历史最值问题,当 pushdown 时要判断左右子树的最大值是否为整个区间的最大值,所以要分为最大值和非最大值部分
另外一个难点在于 pushdown

  • 时间复杂度:O(mlog2n)

代码

// Problem: P6242 【模板】线段树 3 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P6242 // Memory Limit: 500 MB // Time Limit: 3500 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> // #define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=5e5+5,inf=0x3f3f3f3f; int n,m,a[N]; struct Tr { int l,r; int mxa,lmxa,mxb,cnt; int mxadd,nmxadd,mxmx,nmxmx; LL sum; }tr[N<<2]; void pushup(int p) { tr[p].mxa=max(tr[p<<1].mxa,tr[p<<1|1].mxa); tr[p].mxb=max(tr[p<<1].mxb,tr[p<<1|1].mxb); tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum; if(tr[p<<1].mxa==tr[p<<1|1].mxa) tr[p].lmxa=max(tr[p<<1].lmxa,tr[p<<1|1].lmxa), tr[p].cnt=tr[p<<1].cnt+tr[p<<1|1].cnt; else if(tr[p<<1].mxa>tr[p<<1|1].mxa) tr[p].lmxa=max(tr[p<<1].lmxa,tr[p<<1|1].mxa), tr[p].cnt=tr[p<<1].cnt; else tr[p].lmxa=max(tr[p<<1|1].lmxa,tr[p<<1].mxa), tr[p].cnt=tr[p<<1|1].cnt; } void change(int k1,int k2,int k3,int k4,int p) { tr[p].sum+=1ll*k1*tr[p].cnt+1ll*k2*(tr[p].r-tr[p].l+1-tr[p].cnt); tr[p].mxb=max(tr[p].mxb,tr[p].mxa+k3); tr[p].mxa+=k1; if(tr[p].lmxa!=-inf)tr[p].lmxa+=k2; tr[p].mxmx=max(tr[p].mxmx,tr[p].mxadd+k3); tr[p].nmxmx=max(tr[p].nmxmx,tr[p].nmxadd+k4); tr[p].mxadd+=k1; tr[p].nmxadd+=k2; } void pushdown(int p) { int mx=max(tr[p<<1].mxa,tr[p<<1|1].mxa); if(mx==tr[p<<1].mxa) change(tr[p].mxadd,tr[p].nmxadd,tr[p].mxmx,tr[p].nmxmx,p<<1); else change(tr[p].nmxadd,tr[p].nmxadd,tr[p].nmxmx,tr[p].nmxmx,p<<1); if(mx==tr[p<<1|1].mxa) change(tr[p].mxadd,tr[p].nmxadd,tr[p].mxmx,tr[p].nmxmx,p<<1|1); else change(tr[p].nmxadd,tr[p].nmxadd,tr[p].nmxmx,tr[p].nmxmx,p<<1|1); tr[p].mxadd=tr[p].nmxadd=tr[p].mxmx=tr[p].nmxmx=0; } void build(int p,int l,int r) { tr[p]={l,r}; if(l==r) { tr[p].sum=tr[p].mxa=tr[p].mxb=a[l]; tr[p].cnt=1; tr[p].lmxa=-inf; return ; } int mid=l+r>>1; build(p<<1,l,mid),build(p<<1|1,mid+1,r); pushup(p); } void modify_add(int p,int l,int r,int k) { if(l<=tr[p].l&&tr[p].r<=r) { tr[p].sum+=1ll*k*(tr[p].r-tr[p].l+1); tr[p].mxa+=k; tr[p].mxb=max(tr[p].mxb,tr[p].mxa); if(tr[p].lmxa!=-inf)tr[p].lmxa+=k; tr[p].mxadd+=k; tr[p].nmxadd+=k; tr[p].mxmx=max(tr[p].mxmx,tr[p].mxadd); tr[p].nmxmx=max(tr[p].nmxmx,tr[p].nmxadd); return ; } pushdown(p); int mid=tr[p].l+tr[p].r>>1; if(l<=mid) modify_add(p<<1,l,r,k); if(r>mid) modify_add(p<<1|1,l,r,k); pushup(p); } void modify_min(int p,int l,int r,int v) { if(tr[p].mxa<=v)return ; if(l<=tr[p].l&&tr[p].r<=r&&tr[p].lmxa<v) { int t=v-tr[p].mxa; tr[p].sum+=1ll*t*tr[p].cnt; tr[p].mxadd+=t; tr[p].mxa=v; return ; } pushdown(p); int mid=tr[p].l+tr[p].r>>1; if(l<=mid) modify_min(p<<1,l,r,v); if(r>mid) modify_min(p<<1|1,l,r,v); pushup(p); } LL ask_sum(int p,int l,int r) { if(l<=tr[p].l&&tr[p].r<=r)return tr[p].sum; LL res=0; int mid=tr[p].l+tr[p].r>>1; pushdown(p); if(l<=mid)res+=ask_sum(p<<1,l,r); if(r>mid)res+=ask_sum(p<<1|1,l,r); return res; } int ask_maxa(int p,int l,int r) { if(l<=tr[p].l&&tr[p].r<=r)return tr[p].mxa; int res=-inf; int mid=tr[p].l+tr[p].r>>1; pushdown(p); if(l<=mid)res=max(res,ask_maxa(p<<1,l,r)); if(r>mid)res=max(res,ask_maxa(p<<1|1,l,r)); return res; } int ask_maxb(int p,int l,int r) { if(l<=tr[p].l&&tr[p].r<=r)return tr[p].mxb; int res=-inf; int mid=tr[p].l+tr[p].r>>1; pushdown(p); if(l<=mid)res=max(res,ask_maxb(p<<1,l,r)); if(r>mid)res=max(res,ask_maxb(p<<1|1,l,r)); return res; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]); build(1,1,n); while(m--) { int op,l,r,k,v; scanf("%d%d%d",&op,&l,&r); if(op==1) { scanf("%d",&k); modify_add(1,l,r,k); } else if(op==2) { scanf("%d",&v); modify_min(1,l,r,v); } else if(op==3) printf("%lld\n",ask_sum(1,l,r)); else if(op==4) printf("%d\n",ask_maxa(1,l,r)); else printf("%d\n",ask_maxb(1,l,r)); } return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16805097.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示