首页 > 其他分享 >线段树历史值

线段树历史值

时间:2023-11-09 09:45:24浏览次数:39  
标签:历史 ma rs int max 线段 mid ls

P6242 【模板】线段树 3

支持区间加,区间取 \(\min\),区间求和,区间 \(\max\),区间历史 \(\max\)。

先提一嘴吉司机。

就是对线段树的每个节点记录最大值,严格次大值和最大值个数,只在 \(se<v<mx\) 的区间操作,否则向下递归。如果没有区间加,复杂度势能分析是 \(O((n+m)\log n)\) 的,否则为 \(O(m\log^2 n)\)。

考虑 \(\operatorname{pushdown}\) 需要的 \(\mathrm{tag}\)。

  • \(\mathrm{tag1}\):区间 \(\max\) 的懒标记。

  • \(\mathrm{tag2}\):区间非 \(\max\) 的懒标记。

  • \(\mathrm{tag3}\):区间 \(\max\) 的懒标记的最大值。

  • \(\mathrm{tag4}\):区间非 \(\max\) 的懒标记的最大值。

注意要先更新历史值再更新当前值。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define N 500010
#define inf 2e9
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
#define sum(x) tr[x].sum
#define len(x) tr[x].len
#define ma(x) tr[x].ma
#define cnt(x) tr[x].cnt
#define se(x) tr[x].se
#define mb(x) tr[x].mb
#define add1(x) tr[x].add1
#define add2(x) tr[x].add2
#define add3(x) tr[x].add3
#define add4(x) tr[x].add4
struct Tree{
	ll sum;int len;
	int ma,cnt,se,mb;
	int add1,add2,add3,add4;
}tr[N<<2];
#define ls p<<1
#define rs p<<1|1
void pushup(int p){
	sum(p)=sum(ls)+sum(rs);
	ma(p)=max(ma(ls),ma(rs)),mb(p)=max(mb(ls),mb(rs));
	if(ma(ls)==ma(rs))
		se(p)=max(se(ls),se(rs)),cnt(p)=cnt(ls)+cnt(rs);
	else if(ma(ls)>ma(rs))
		se(p)=max(se(ls),ma(rs)),cnt(p)=cnt(ls);
	else
		se(p)=max(ma(ls),se(rs)),cnt(p)=cnt(rs);
}
void change(int p,int k1,int k2,int k3,int k4){
	sum(p)+=1ll*k1*cnt(p)+1ll*k2*(len(p)-cnt(p));
	mb(p)=max(mb(p),ma(p)+k3),ma(p)+=k1;
	if(se(p)!=-inf)se(p)+=k2;
	add3(p)=max(add3(p),add1(p)+k3);
	add4(p)=max(add4(p),add2(p)+k4);
	add1(p)+=k1,add2(p)+=k2;
}
void pushdown(int p){
	int mx=max(ma(ls),ma(rs));
	if(ma(ls)==mx)
		change(ls,add1(p),add2(p),add3(p),add4(p));
	else change(ls,add2(p),add2(p),add4(p),add4(p));
	if(ma(rs)==mx)
		change(rs,add1(p),add2(p),add3(p),add4(p));
	else change(rs,add2(p),add2(p),add4(p),add4(p));
	add1(p)=add2(p)=add3(p)=add4(p)=0;
}
void build(int p,int l,int r){
	len(p)=r-l+1;
	if(l==r){
		sum(p)=ma(p)=mb(p)=read();
		cnt(p)=1,se(p)=-inf;
		return;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid),build(rs,mid+1,r);
	pushup(p);
}
ll qsum(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)return sum(p);
	int mid=(l+r)>>1;pushdown(p);
	ll ret=0;
	if(L<=mid)ret+=qsum(ls,l,mid,L,R);
	if(R>mid)ret+=qsum(rs,mid+1,r,L,R);
	return ret;
}
int qma(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)return ma(p);
	int mid=(l+r)>>1;pushdown(p);
	if(R<=mid)return qma(ls,l,mid,L,R);
	if(L>mid)return qma(rs,mid+1,r,L,R);
	return max(qma(ls,l,mid,L,R),qma(rs,mid+1,r,L,R));
}
int qmb(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)return mb(p);
	int mid=(l+r)>>1;pushdown(p);
	if(R<=mid)return qmb(ls,l,mid,L,R);
	if(L>mid)return qmb(rs,mid+1,r,L,R);
	return max(qmb(ls,l,mid,L,R),qmb(rs,mid+1,r,L,R));
}
void uadd(int p,int l,int r,int L,int R,int k){
	if(L<=l&&r<=R){
		sum(p)+=1ll*k*len(p);
		ma(p)+=k,mb(p)=max(mb(p),ma(p));
		if(se(p)!=-inf)se(p)+=k;
		add1(p)+=k,add2(p)+=k;
		add3(p)=max(add3(p),add1(p)),add4(p)=max(add4(p),add2(p));
		return;
	}
	int mid=(l+r)>>1;pushdown(p);
	if(L<=mid)uadd(ls,l,mid,L,R,k);
	if(R>mid)uadd(rs,mid+1,r,L,R,k);
	pushup(p);
}
void umin(int p,int l,int r,int L,int R,int v){
	if(L>r||R<l||v>=ma(p))return;
	if(L<=l&&r<=R&&se(p)<v){
		int k=ma(p)-v;
		sum(p)-=1ll*cnt(p)*k;
		ma(p)=v,add1(p)-=k;
		return;
	}
	int mid=(l+r)>>1;pushdown(p);
	umin(ls,l,mid,L,R,v);
	umin(rs,mid+1,r,L,R,v);
	pushup(p);
}
int n,m;
int main(){
	n=read(),m=read();
	build(1,1,n);
	for(int opt,l,r;m;m--){
		opt=read(),l=read(),r=read();
		if(opt==1)uadd(1,1,n,l,r,read());
		if(opt==2)umin(1,1,n,l,r,read());
		if(opt==3)printf("%lld\n",qsum(1,1,n,l,r));
		if(opt==4)printf("%d\n",qma(1,1,n,l,r));
		if(opt==5)printf("%d\n",qmb(1,1,n,l,r));
	}
	
	return 0;
}

标签:历史,ma,rs,int,max,线段,mid,ls
From: https://www.cnblogs.com/SError0819/p/17819020.html

相关文章

  • 原点到线段的垂足
    原理:1) 求出向量ao在ab上的投影距离2)a沿着ab方向移动投影距离就是垂足点的位置 //获得原点到直线ab的垂点publicstaticVector2GetPerpendicularToOrigin(Vector2a,Vector2b){varab=b-a;varao=Vector2.zero-a;floatproj=Vector2.D......
  • 如何使用git将某个文件回退到历史版本
    1.查看提交历史gitlogcommit4fe5108e0ca86d439f0da61751fac5845ec64f5c3commit38f9efd1f004996330a78c4b78372ba7c37469892commit5617205b96685ee157b67f3d66c71aa24cc378601会出现一些commitid2.找到需要回退的文件路径,如api/v2/s.php3.开始回退,要把api/v......
  • ​​Android平台GB28181历史视音频文件回放规范解读及技术实现
     技术背景在实现GB28181历史视音频文件回放之前,我们已完成了历史视音频文件检索和下载,历史视音频回放,在GB28181平台非常重要,比如执法记录仪等前端设备,默认录像数据存储在前端设备侧,如果需要上传到平台统一保存,除了到工作站拷贝外,还可以通过GB28181的历史视音频文件下载到指挥中心......
  • 这是我在51CTO的第一篇博客,历史车轮缓缓开动
    开始学习C语言,学习令人充实,进步让人愉悦,记录路途美景与期盼在一个有序数组中查找具体的某个数字n。编写intbinsearch(intx,intv[],intn);功能:在v[0]<=v[1]<=v[2]<=…<=v[n-1]的数组中查找x假设有一个数组如下,查找数字7遍历法:#include<stdio.h>intmain(){ intarr[]={1,2,......
  • 图解串一串 webpack 的历史和核心功能
    提到打包工具,可能你会首先想到webpack。那没有webpack之前,都是怎么打包的呢?webpack都有哪些功能?为什么这么设计呢?这篇文章我们就来一起探究一下。其实之前都不打包的,就是js、css分别用对应的工具编译下,然后在html里引入。比如js用babel编译,再用terser压缩、css用sa......
  • 向量叉乘判断两点是否在线段同侧
    ap1×ab与ap2×ab的结果异号,则表示两点在线段两侧;同号则表示在线段同侧 有一个点在线段上或两个点都在线段上,当做在线段同侧处理 //两点是否在线段同侧publicstaticboolIsTwoPointSameSideOfSegment(Vector2a,Vector2b,Vector2p1,Vector2p2){vara_p1=......
  • 用线段树来接树状数组类的问题
    大致解决的问题就是区间查询以及单点的修改#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=5e5+10;inta[N],tag[N<<2];struct{ struct{ intl,r,sum; }tr[N<<2]; voidpush_up(inti){ tr[i].sum=tr[i<<1].sum+tr[i<......
  • 自然语言处理历史史诗:NLP的范式演变与Python全实现
    本文全面回顾了自然语言处理(NLP)从20世纪50年代至今的历史发展。从初创期的符号学派和随机学派,到理性主义时代的逻辑和规则范式,再到经验主义和深度学习时代的数据驱动方法,以及最近的大模型时代,NLP经历了多次技术革新和范式转换。文章不仅详细介绍了每个阶段的核心概念和技术,还提供......
  • 向量点乘判断点是否在线段上
    几种要考虑的情况1)点p和线段断点a,b重叠,pa•ab=pa.x*pa.y+ab.x*ab.y=02) pa,pb共线,则pa×pb=02-1)p在线段ab上,此时pa,pb的夹角为180度,cos(180)=-1,pa•ab=-|pa|*|ab|2-2)p在线段ab外,此时pa,pb的夹角为0度,cos(0)=1,pa•ab=|pa|*|ab|4)pa,pb不共线,cos(钝角)<0,cos(......
  • Hadoop-3.3.3分布式集群的文件配置,启动hadoop历史服务和启动日志聚集
    一、分布式集群的文件配置涉及$HADOOP_HOME/etc/hadoop路径下的5个文件workers、core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml首先修改workers进入$HADOOP_HOME/etc/hadoopvimworkers编辑自己的主机节点。注意!每行一个,默认为把本机节点同时作为数据节......