首页 > 其他分享 >P6242 【模板】线段树 3

P6242 【模板】线段树 3

时间:2022-10-19 09:44:32浏览次数:80  
标签:int 线段 P6242 leq 区间 最大值 模板 define

题目链接

P6242 【模板】线段树 3

【模板】线段树 3

题目背景

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

题目描述

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

  • 1 l r k:对于所有的 \(i\in[l,r]\),将 \(A_i\) 加上 \(k\)(\(k\) 可以为负数)。
  • 2 l r v:对于所有的 \(i\in[l,r]\),将 \(A_i\) 变成 \(\min(A_i,v)\)。
  • 3 l r:求 \(\sum_{i=l}^{r}A_i\)。
  • 4 l r:对于所有的 \(i\in[l,r]\),求 \(A_i\) 的最大值。
  • 5 l r:对于所有的 \(i\in[l,r]\),求 \(B_i\) 的最大值。

在每一次操作后,我们都进行一次更新,让 \(B_i\gets\max(B_i,A_i)\)。

输入格式

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

第二行包含 \(n\) 个整数 \(A_1,A_2,\cdots,A_n\),表示数列 \(A\)。

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

输出格式

对于 \(op\in\{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,m\leq 5000\);
  • 对于测试点 \(3,4\),满足 \(op\in\{1,2,3,4\}\);
  • 对于测试点 \(5,6\),满足 \(op\in\{1,3,4,5\}\);
  • 对于全部测试数据,保证 \(1\leq n,m\leq 5\times 10^5\),\(-5\times10^8\leq A_i\leq 5\times10^8\),\(op\in[1,5]\),\(1 \leq l\leq r \leq n\),\(-2000\leq k\leq 2000\),\(-5\times10^8\leq v\leq 5\times10^8\)。

提示

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

解题思路

吉司机线段树

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

  • 时间复杂度:\(O(mlog^2)\)

代码

// 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;
}

标签:int,线段,P6242,leq,区间,最大值,模板,define
From: https://www.cnblogs.com/zyyun/p/16805097.html

相关文章

  • 快速缩略模板. ?imageView2/1/w/80/h/80
    通过 imageView2 接口提供常用图片处理模板。开发者根据业务需求,只需在下载URL后面附加相应的参数,就可以生成相应的缩略图。处理图片原图大小不超过32MB、宽高不超过30......
  • pentlab第三方镜像模板
    注意:使用此模板前,先把你的pentlab升级到最新版本,5.0.1链接:https://pan.baidu.com/s/1XNYo7CjD3ddSoC1gvHIt1w提取码:8a8i 更新模板引擎,对amdintel处理器做了区分使用......
  • 2022下半年 Acwing 第二篇:归并模板
    归并其实和快排比较类似,所以模板的记忆也大差不差。不能省懒!voidmerge_sort(intq[],intl,intr){if(l>=r)return;intmid=l+r>>1;merge_s......
  • 浅谈线段树
    浅谈线段树Segment_TreeByxiaruize引言OI中,有一种好玩的游戏,叫做码线段树,那么线段树是什么???线段树的目的线段树主要用于在区间上动态维护一些值(如最大值,最小......
  • 干货 | Elasticsearch基础但非常有用的功能之二:模板
    Elasticsearch最少必要知识实战教程直播回放1、引言业务场景1:数据量非常大,需要进行索引生命周期管理,按日期划分索引,要求多个索引的Mapping一致,每次手动创建或者脚本创......
  • 线段树 __ 复习
    线段树的结构为什么叫线段树?因为它是把原序列以及其子序列(一个个线段)组织成一棵树的形式。树的根节点为原序列,子节点依次对半分序列,直到叶节点,叶节点是单个数,也没办法再......
  • 分享几个智慧城市可视化系统模板
    分享几个我觉得很泛用的智慧城市可视化大屏模板,功能齐全且强大,画面美观且酷炫! 模板一:智慧城市可视化应用管理平台整合城市相关数据资源,对公共环境、人员民生、公共安......
  • 线段树应用模板题
    利用刚学的线段树写一道模板题https://www.acwing.com/problem/content/1272/这里不需要更新修改,但是要求的却是最大值因而pushup时,也是取max,build与模板一样查询的que......
  • P6492 [COCI2010-2011#6] STEP(线段树维护左右区间pushup)
    题目链接题目大意:\(~~\)初始给定一个长度为n的字符序列a,初始序列中全是\(~\)L\(~~\)共有q次修改,修改a\(_{x}\)为:L\(\rightarrow\)\(~~\)or\(~~\)R\(\rightarrow\)L\(......
  • [软件方法]如何制作EA的文档模板
    以下步骤以制作用例规约模板为例讲解如何自己制作EA的文档模板。只要模板合适,EA模型里的各种元素都可以以想要的排版和格式出现在文档中。【步骤1】在EA主界面上选择Publish......