首页 > 其他分享 >吉司机线段树

吉司机线段树

时间:2023-12-21 21:56:35浏览次数:27  
标签:cnt rs int 线段 t2 mx1 司机 ls

\(mxb\) 为历史最大值,\(tg1,tg2,tg3,tg4\) 分别对应最大值真实 \(tag\) ,其他值真实 \(tag\) ,最大值最大 \(tag\) ,其它值最大 \(tag\)

#include<bits/stdc++.h>
using namespace std;
#define N 500005
#define int long long
int n,m;
int a[N];
struct TREE{
	int sum[N*4],mxb[N*4],mx1[N*4],cnt[N*4],mx2[N*4],tot[N*4];
	int tg1[N*4],tg2[N*4],tg3[N*4],tg4[N*4];
	void up(int p){
		int ls=p*2,rs=p*2+1;
		sum[p]=sum[ls]+sum[rs];
		mxb[p]=max(mxb[ls],mxb[rs]);
		if(mx1[ls]==mx1[rs]){
			mx1[p]=mx1[ls],cnt[p]=cnt[ls]+cnt[rs];
			mx2[p]=max(mx2[ls],mx2[rs]);
		}
		else if(mx1[ls]>mx1[rs]){
			mx1[p]=mx1[ls],cnt[p]=cnt[ls];
			mx2[p]=max(mx2[ls],mx1[rs]);
		}
		else{
			mx1[p]=mx1[rs],cnt[p]=cnt[rs];
			mx2[p]=max(mx2[rs],mx1[ls]);
		}
	}
	void upd(int p,int t1,int t2,int t3,int t4){
		sum[p]+=t1*cnt[p]+t2*(tot[p]-cnt[p]);
		mxb[p]=max(mxb[p],mx1[p]+t3);
		mx1[p]+=t1;
		if(mx2[p]!=-2e9) mx2[p]+=t2;
		tg3[p]=max(tg3[p],tg1[p]+t3),tg1[p]+=t1;
		tg4[p]=max(tg4[p],tg2[p]+t4),tg2[p]+=t2;
	}
	void down(int p){
		int t1=tg1[p],t2=tg2[p],t3=tg3[p],t4=tg4[p],ls=p*2,rs=p*2+1;
		int mx=max(mx1[ls],mx1[rs]);
		if(mx==mx1[ls]) upd(ls,t1,t2,t3,t4);
		else upd(ls,t2,t2,t4,t4);
		if(mx==mx1[rs]) upd(rs,t1,t2,t3,t4);
		else upd(rs,t2,t2,t4,t4);
		tg1[p]=tg2[p]=tg3[p]=tg4[p]=0;
	}
	void build(int p,int l,int r){
		tot[p]=r-l+1;
		if(l==r){
			sum[p]=mxb[p]=mx1[p]=a[l];
			mx2[p]=-2e9,cnt[p]=1;
			return ;
		}
		int mid=(l+r)>>1;
		build(p*2,l,mid);
		build(p*2+1,mid+1,r);
		up(p);
	}
	void add(int p,int l,int r,int x,int y,int z){
		if(x<=l&&r<=y){
			sum[p]+=z*(r-l+1),mx1[p]+=z,mxb[p]=max(mxb[p],mx1[p]);
			tg1[p]+=z,tg3[p]=max(tg3[p],tg1[p]);
			tg2[p]+=z,tg4[p]=max(tg4[p],tg2[p]);
			if(mx2[p]!=-2e9) mx2[p]+=z;
			return ;
		}
		down(p);
		int mid=(l+r)>>1;
		if(x<=mid) add(p*2,l,mid,x,y,z);
		if(mid<y) add(p*2+1,mid+1,r,x,y,z);
		up(p);
	}
	void qmn(int p,int l,int r,int x,int y,int z){
		if(z>=mx1[p]) return ;
		if(x<=l&&r<=y&&z>mx2[p]){
			sum[p]-=cnt[p]*(mx1[p]-z);
			tg1[p]-=(mx1[p]-z),mx1[p]=z;//tg3²»¸üÐÂÊÇÒòΪֻ»á¼õÉÙ 
			return ;
		}
		down(p);
		int mid=(l+r)>>1;
		if(x<=mid) qmn(p*2,l,mid,x,y,z);
		if(mid<y) qmn(p*2+1,mid+1,r,x,y,z);
		up(p); 
	}
	int sum_(int p,int l,int r,int x,int y){
		if(x<=l&&r<=y) return sum[p];
		down(p);
		int mid=(l+r)>>1,ans=0;
		if(x<=mid) ans+=sum_(p*2,l,mid,x,y);
		if(mid<y) ans+=sum_(p*2+1,mid+1,r,x,y);
		return ans;
	}
	int maxa(int p,int l,int r,int x,int y){
		if(x<=l&&r<=y) return mx1[p];
		down(p);
		int mid=(l+r)>>1,ans=-2e9;
		if(x<=mid) ans=max(ans,maxa(p*2,l,mid,x,y));
		if(mid<y) ans=max(ans,maxa(p*2+1,mid+1,r,x,y));
		return ans;
	}
	int maxb(int p,int l,int r,int x,int y){
		if(x<=l&&r<=y) return mxb[p];
		down(p);
		int mid=(l+r)>>1,ans=-2e9;
		if(x<=mid) ans=max(ans,maxb(p*2,l,mid,x,y));
		if(mid<y) ans=max(ans,maxb(p*2+1,mid+1,r,x,y));
		return ans;
	}
}T;
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	T.build(1,1,n);
	while(m--){
		int op,x,y,z;
		scanf("%lld%lld%lld",&op,&x,&y);
		if(op<=2) scanf("%lld",&z);
		if(op==1) T.add(1,1,n,x,y,z);
		if(op==2) T.qmn(1,1,n,x,y,z);
		if(op==3) printf("%lld\n",T.sum_(1,1,n,x,y));
		if(op==4) printf("%lld\n",T.maxa(1,1,n,x,y));
		if(op==5) printf("%lld\n",T.maxb(1,1,n,x,y));
	}
	return 0;
}

标签:cnt,rs,int,线段,t2,mx1,司机,ls
From: https://www.cnblogs.com/hubingshan/p/17920203.html

相关文章

  • 线段树与历史最值和区间最值问题
    线段树与历史最值问题P4314CPU监控Description给定数组\(\{a_i\}\),维护以下操作。定义一个辅助数组\(\{b_i\}\),每次操作完后令\(b_i=\max(a_i,b_i)\)。查询\(\max_{i=l}^{r}a_i\)(区间最值)查询\(\max_{i=l}^{r}b_i\)(历史最值)\(\foralli\in[l,r]\),\(a_i\gets......
  • syoj.1827. 线段传送带题解
    前情提要-三分1827.线段传送带P2571[SCOI2010]传送带省流:三分套三分。在二维平面上有两个传送带,一个从A点到B点,一个从C点到D点,速度分别是p和q,在平面内其他点的速度为r。求A点到D点的最小速度。考虑从A到D的路程一定是\(AE+EF+FD\),即通过这两个点连......
  • 线段树详解
    定义什么是线段树线段树是一种二叉搜索树,每个节点都存储了一个区间的问题。能够解决的问题序列维护修改以及查询区间上的最值、求和等,修改和查询的时间复杂度为\(O\)(\(log\)\(n\))。与其他RMQ算法的区别算法适用范围优点缺点线段树动态可执行的操作......
  • 简单线段树
    一、什么是线段树?线段树是怎样的树形结构?线段树是一种二叉搜索树,每个结点都存储了一个区间,也可以理解成一个线段,你要从这些线段上进行搜索操作得到你想要的答案。线段树能够解决什么样的问题?线段树的适用范围很广,可以在线维护修改以及查询区间上的最值,求和。......
  • CF1784C Monsters (hard version) 题解 线段树
    题目链接:https://codeforces.com/problemset/problem/1784/C题目大意:你面前有\(n\)只怪兽,每只怪兽都有一个初始血量,你可以进行两类操作:操作1:选择任意一个血量大于\(0\)的怪兽,并将它的血量降低\(1\);操作2:将所有存活的怪物的血量各自减去\(1\),如果存在怪物的血量恰好降为......
  • 线段树
    线段树什么是线段树线段树(英语:Segmenttree)是一种二叉树形数据结构,1977年由JonLouisBentley发明[1],用以存储区间或线段,并且允许快速查询结构内包含某一点的所有区间。一个包含n个区间的线段树,空间复杂度为O(n),查询的时间复杂度则为O(logn+k)},其中k是匹配条件的区间数量。此......
  • 【UVCAD】- 多段线教程,及与线段的区别
    【UVCAD】手机二维CAD建模,不止是看图UVCAD专注于二维(2D)的移动计算机辅助绘图(CAD)。UVCAD具有触摸优化的直观界面和工具。使用UVCAD,您可以在触摸屏上用手指或铅笔进行真正的2D绘图、2D建模和2D设计。对于需要易于使用的工具来更快、更精确地创建图纸的设计师和绘图员来说,UVC......
  • 刷题 ST表、单调栈、线段树->区间最值
    2023.12.13cf1904D2解题思路首先,a[i]大于b[i]时肯定不行,等于就满足了,直接过掉其次,要想使得a[i]等于b[i],就要在a[i]左右找最近的j使得a[j]=b[i](最近的最优,可证)k是i和j中间的一个数,想要满足题意,要满足以下两个条件(a[j]=b[i])1.ak<aj,即max(区间[i,j]中的ak)2.bk>bi,即min(区间......
  • 【线段树入门】P3353 在你窗外闪耀的星星(区间求和)
    这题正解是前缀和,我用线段树练练手><11//笔记-自用22//#pragmaGCCoptimize("Ofast")33//#pragmaGCCoptimize("unroll-loops")44#define_CRT_SECURE_NO_WARNINGS55#defineAll(a)a.begin(),a.end()66#defineINF214748364777......
  • 【线段树入门】 P1198 最大数(区间最大值+无懒标记+末尾插入)
    1//笔记-自用2//#pragmaGCCoptimize("Ofast")3//#pragmaGCCoptimize("unroll-loops")4#define_CRT_SECURE_NO_WARNINGS5#defineAll(a)a.begin(),a.end()6#defineINF21474836477#include<bits/stdc++.h>8#include<nu......