【校内模拟】送分题(双重吉司机线段树)

本文深入探讨了一种特殊的线段树——吉司机线段树,通过实战案例详细讲解了如何使用该数据结构解决复杂的问题,包括区间更新、区间查询等操作,并附带完整的代码实现。

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

从前有一棵线段树,只会单点加减和单点询问。然后它长大了,会区间加减和区间询问了。它想成为线段树中的国王,但是成为国王的条件是掌握区间取 max 和区间历史最值和两种终极技能,但是它现在并不会,所以需要你的帮助。

给出一个长度为n的序列a,进行m次操作,有4种操作:

  1. 给出 l,r,x,∀i∈[l,r],ai=max⁡(ai,x)l, r, x, ∀i ∈ [l, r], a_i = \max(a_i, x)l,r,x,i[l,r],ai=max(ai,x)
  2. 给出 l,r,x,∀i∈[l,r],ai=ai+xl,r, x, ∀i ∈ [l, r], a_i = a_i + xl,r,x,i[l,r],ai=ai+x
  3. 给出 l,r,求∑ai,i∈[l,r]l, r,求∑ a_i , i ∈ [l, r]l,r,ai,i[l,r]
  4. 给出 l,r,求∑bi,i∈[l,r]l,r,求∑ b_i , i ∈ [l, r]l,r,bi,i[l,r]

序列𝑏最开始和𝑎相同,每次操作后, ∀𝑖 ∈ [1, 𝑛], 𝑏𝑖 = min(𝑏𝑖, 𝑎𝑖)


题解:

设序列c=a−bc=a-bc=ab

aaa进行吉司机线段树式的维护。

对按照这个位置是否是集合中的最小值对ccc分两类维护吉司机线段树。

然后就没了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	template<typename T>
	inline T get(){
		char c;bool f=false;
		while(!isdigit(c=gc()))f=c=='-';T num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return f?-num:num;
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=1e5+7,INF=1e9;

int n,m,a[N];

struct node{
	int mn,ct,sub,adm,ads,siz;
	ll sum;
	inline void clear_tag(){adm=ads=0;}
	inline void clear(){mn=INF,ct=0,sub=INF+1,siz=0,sum=0;}
	inline void init(int v){
		adm=ads=0;
		if(v==INF)clear();
		else mn=v,ct=1,sub=INF,siz=1,sum=v;
	}
	inline void update(int dm,int ds){
		mn+=dm,adm+=dm;
		if(sub<INF)sub+=ds,ads+=ds;
		sum+=(ll)ct*dm+(ll)(siz-ct)*ds;
	}
	inline void get(cs node &p){
		if(p.mn==mn)ct+=p.ct,sub=std::min(sub,p.sub);
		else if(p.mn<mn)sub=std::min(mn,p.sub),mn=p.mn,ct=p.ct;
		else sub=std::min(sub,p.mn);
		siz+=p.siz,sum+=p.sum;
	}
	inline void trans(node &p)cs{
		if(adm||ads)if(p.mn+adm==mn)p.update(adm,ads);
		else p.update(ads,ads);
	}
};

namespace SGT{
#define lc u<<1
#define rc u<<1|1
	node t1[N<<2],t2[N<<2],t3[N<<2];
	
	inline void pushup(int u){
		t1[u].clear(),t2[u].clear(),t3[u].clear();
		t1[u].get(t1[lc]),t1[u].get(t1[rc]);
		if(t1[u].mn==t1[lc].mn)t2[u].get(t2[lc]);
		else t3[u].get(t2[lc]);
		if(t1[u].mn==t1[rc].mn)t2[u].get(t2[rc]);
		else t3[u].get(t2[rc]);
		t3[u].get(t3[lc]);t3[u].get(t3[rc]);
	}
	
	inline void pushdown(int u){
		t1[u].trans(t1[lc]),t1[u].trans(t1[rc]);
		if(t1[u].mn==t1[lc].mn)t2[u].trans(t2[lc]);
		else t3[u].trans(t2[lc]);
		if(t1[u].mn==t1[rc].mn)t2[u].trans(t2[rc]);
		else t3[u].trans(t2[rc]);
		t3[u].trans(t3[lc]),t3[u].trans(t3[rc]);
		t1[u].clear_tag();t2[u].clear_tag();t3[u].clear_tag();
	}
	
	inline void build(int u,int l,int r){
		if(l==r){
			t1[u].init(a[l]);
			t2[u].init(0);
			t3[u].init(INF);
			return ;
		}
		int mid=l+r>>1;
		build(lc,l,mid);build(rc,mid+1,r);
		pushup(u);
	}
	
	inline void dfs1(int u,int l,int r,int delta,int val){
		if(t1[u].mn==val){
			if(t2[u].mn>=-delta)t2[u].update(delta,delta);
			else if(t2[u].sub>=-delta)t2[u].update(-t2[u].mn,delta);
			else {
				pushdown(u);
				int mid=l+r>>1;
				dfs1(lc,l,mid,delta,val);
				dfs1(rc,mid+1,r,delta,val);
				pushup(u);
			}
		}
	}
	
	inline void dfs2(int u,int l,int r,int val){
		if(t1[u].mn>=val)return ;
		else if(t1[u].sub>val){
			int ad=val-t1[u].mn;
			t1[u].update(ad,0);
			dfs1(u,l,r,ad,t1[u].mn);
			return ;
		}
		else {
			pushdown(u);
			int mid=l+r>>1;
			dfs2(lc,l,mid,val);
			dfs2(rc,mid+1,r,val);
			pushup(u);
		}
	}
	
	inline void modify_max(int u,int l,int r,int ql,int qr,int val){
		if(ql<=l&&r<=qr){
			dfs2(u,l,r,val);
		}
		else {
			pushdown(u);
			int mid=l+r>>1;
			if(ql<=mid)modify_max(lc,l,mid,ql,qr,val);
			if(mid<qr)modify_max(rc,mid+1,r,ql,qr,val);
			pushup(u);
		}
	}
	
	inline void dfs(int u,int l,int r,int ad,bool f1,bool f2){
		if(f1){
			if(t2[u].mn>=-ad)t2[u].update(ad,ad),f1=false;
			else if(t2[u].sub>=-ad)t2[u].update(-t2[u].mn,ad),f1=false;
		}
		if(f2){
			if(t3[u].mn>=-ad)t3[u].update(ad,ad),f2=false;
			else if(t3[u].sub>=-ad)t3[u].update(-t3[u].mn,ad),f2=false;
		}
		if(f1||f2){
			pushdown(u);
			int mid=l+r>>1;
			dfs(lc,l,mid,ad,t1[lc].mn==t1[u].mn?f1:f2,f2);
			dfs(rc,mid+1,r,ad,t1[rc].mn==t1[u].mn?f1:f2,f2);
			pushup(u);
		}
	}
	
	inline void modify_add(int u,int l,int r,int ql,int qr,int ad){
		if(ql<=l&&r<=qr){
			t1[u].update(ad,ad);
			dfs(u,l,r,ad,1,1);
		}
		else {
			pushdown(u);
			int mid=l+r>>1;
			if(ql<=mid)modify_add(lc,l,mid,ql,qr,ad);
			if(mid<qr)modify_add(rc,mid+1,r,ql,qr,ad);
			pushup(u);
		}
	}
	
	inline ll query1(int u,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr)return t1[u].sum;
		pushdown(u);
		int mid=l+r>>1;
		if(qr<=mid)return query1(lc,l,mid,ql,qr);
		if(mid<ql)return query1(rc,mid+1,r,ql,qr);
		return query1(lc,l,mid,ql,qr)+query1(rc,mid+1,r,ql,qr);
	}
	
	inline ll query2(int u,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr)return t1[u].sum-t2[u].sum-t3[u].sum;
		pushdown(u);
		int mid=l+r>>1;
		if(qr<=mid)return query2(lc,l,mid,ql,qr);
		if(mid<ql)return query2(rc,mid+1,r,ql,qr);
		return query2(lc,l,mid,ql,qr)+query2(rc,mid+1,r,ql,qr);
	}
#undef lc
#undef rc
}

signed main(){
#ifdef zxyoi
	freopen("sft.in","r",stdin);
#else
#ifndef ONLINE_JUDGE
	freopen("sft.in","r",stdin);freopen("sft.out","w",stdout);
#endif
#endif
	n=gi(),m=gi();
	for(int re i=1;i<=n;++i)a[i]=gi();
	SGT::build(1,1,n);
	while(m--){
		switch(gi()){
			case 1:{
				int l=gi(),r=gi(),x=gi();
				SGT::modify_max(1,1,n,l,r,x);
				break;
			}
			case 2:{
				int l=gi(),r=gi(),x=gi();
				SGT::modify_add(1,1,n,l,r,x);
				break;
			}
			case 3:{
				int l=gi(),r=gi();
				cout<<SGT::query1(1,1,n,l,r)<<"\n";
				break;
			}
			case 4:{
				int l=gi(),r=gi();
				cout<<SGT::query2(1,1,n,l,r)<<"\n";
				break;
			}
		}
	} 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值