II.吉司机线段树

吉司机线段树是一类支持区间所有数对某个数取 \(\min\),以及所有其它线段树操作的线段树。

我们以区间取 \(\min\)、区间求和为例。

其具体实现是,在线段树的每个节点上存储区间最大值、区间次大值、区间最大值出现次数、区间和。显然,所有东西都可以简单维护。

然后,考虑区间取 \(\min\)。在线段树上,大区间被拆成了许多小区间。考虑其中某一个小区间。

假设现在是区间关于某个值 \(x\)\(\min\)。则,若区间最大值不大于 \(x\),显然可以直接 return 了;

\(x\) 比次大值大、比最大值小,则其只会作用于最大值一个值,因此可以直接打 tag,只修改最小值;

\(x\) 小于等于次大值,则修改不很简单,我们继续递归入子区间修改。

可以被证明,若不存在区间修改,复杂度是 \(O(n\log n)\) 的;否则,复杂度 \(O(n\log^2n)\)

它还有一个名字叫 Segment Tree Beats吊打线段树

证明?直接用就行了

II.II.BZOJ#4695. 最假女选手

实际上是吉司机线段树的模板。

经过压行后甚至比上一题还要短是怎么回事啊喂

甚至能够1A

53行极短代码,你值得拥有

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
int a[500100],n,m;
struct SegTree{int mx,smx,mn,smn,cmx,cmn,tagsm;ll sum;}seg[2001000];
#define lson x<<1
#define rson x<<1|1
#define mid ((l+r)>>1)
#define X x,l,r
#define LSON lson,l,mid
#define RSON rson,mid+1,r
void ADD(int x,int l,int r,int y){seg[x].mx+=y,seg[x].mn+=y;if(seg[x].smx!=-inf)seg[x].smx+=y;if(seg[x].smn!=inf)seg[x].smn+=y;seg[x].sum+=1ll*(r-l+1)*y,seg[x].tagsm+=y;}
void MX(int x,int y){if(seg[x].mn==seg[x].mx)seg[x].mn=y;if(seg[x].smn==seg[x].mx)seg[x].smn=y;seg[x].sum+=1ll*seg[x].cmx*(y-seg[x].mx),seg[x].mx=y;}
void MN(int x,int y){if(seg[x].mx==seg[x].mn)seg[x].mx=y;if(seg[x].smx==seg[x].mn)seg[x].smx=y;seg[x].sum-=1ll*seg[x].cmn*(seg[x].mn-y),seg[x].mn=y;}
void pushdown(int x,int l,int r){
	ADD(LSON,seg[x].tagsm),ADD(RSON,seg[x].tagsm),seg[x].tagsm=0;
	if(seg[lson].mx>seg[x].mx)MX(lson,seg[x].mx);if(seg[rson].mx>seg[x].mx)MX(rson,seg[x].mx);
	if(seg[lson].mn<seg[x].mn)MN(lson,seg[x].mn);if(seg[rson].mn<seg[x].mn)MN(rson,seg[x].mn);
}
void pushup(int x){
	seg[x].sum=seg[lson].sum+seg[rson].sum,seg[x].mx=max(seg[lson].mx,seg[rson].mx),seg[x].mn=min(seg[lson].mn,seg[rson].mn),seg[x].cmx=seg[x].cmn=0;
	if(seg[lson].mx==seg[x].mx)seg[x].cmx+=seg[lson].cmx;if(seg[rson].mx==seg[x].mx)seg[x].cmx+=seg[rson].cmx;
	if(seg[lson].mn==seg[x].mn)seg[x].cmn+=seg[lson].cmn;if(seg[rson].mn==seg[x].mn)seg[x].cmn+=seg[rson].cmn;
	seg[x].smx=max(seg[x].mx==seg[lson].mx?seg[lson].smx:seg[lson].mx,seg[x].mx==seg[rson].mx?seg[rson].smx:seg[rson].mx);
	seg[x].smn=min(seg[x].mn==seg[lson].mn?seg[lson].smn:seg[lson].mn,seg[x].mn==seg[rson].mn?seg[rson].smn:seg[rson].mn);
}
void build(int x,int l,int r){if(l==r){seg[x].sum=seg[x].mx=seg[x].mn=a[l],seg[x].smx=-inf,seg[x].smn=inf,seg[x].cmx=seg[x].cmn=1;return;}build(LSON),build(RSON),pushup(x);}
void modifyadd(int x,int l,int r,int L,int R,int val){if(l>R||r<L)return;if(L<=l&&r<=R){ADD(X,val);return;}pushdown(X),modifyadd(LSON,L,R,val),modifyadd(RSON,L,R,val),pushup(x);}
void checkmax(int x,int l,int r,int L,int R,int val){
	if(l>R||r<L||seg[x].mn>=val)return;if(L<=l&&r<=R&&seg[x].smn>val){MN(x,val);return;}
	pushdown(X),checkmax(LSON,L,R,val),checkmax(RSON,L,R,val),pushup(x);
}
void checkmin(int x,int l,int r,int L,int R,int val){
	if(l>R||r<L||seg[x].mx<=val)return;if(L<=l&&r<=R&&seg[x].smx<val){MX(x,val);return;}
	pushdown(X),checkmin(LSON,L,R,val),checkmin(RSON,L,R,val),pushup(x);
}
ll asksum(int x,int l,int r,int L,int R){if(l>R||r<L)return 0;if(L<=l&&r<=R)return seg[x].sum;pushdown(X);return asksum(LSON,L,R)+asksum(RSON,L,R);}
int askmx(int x,int l,int r,int L,int R){if(l>R||r<L)return -inf;if(L<=l&&r<=R)return seg[x].mx;pushdown(X);return max(askmx(LSON,L,R),askmx(RSON,L,R));}
int askmn(int x,int l,int r,int L,int R){if(l>R||r<L)return inf;if(L<=l&&r<=R)return seg[x].mn;pushdown(X);return min(askmn(LSON,L,R),askmn(RSON,L,R));}
int main(){
	scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);build(1,1,n);
	scanf("%d",&m);for(int i=1,tp,l,r,x;i<=m;i++){
		scanf("%d%d%d",&tp,&l,&r);
		if(tp==1)scanf("%d",&x),modifyadd(1,1,n,l,r,x);
		if(tp==2)scanf("%d",&x),checkmax(1,1,n,l,r,x);
		if(tp==3)scanf("%d",&x),checkmin(1,1,n,l,r,x);
		if(tp==4)printf("%lld\n",asksum(1,1,n,l,r));
		if(tp==5)printf("%d\n",askmx(1,1,n,l,r));
		if(tp==6)printf("%d\n",askmn(1,1,n,l,r));
	}
	return 0;
}