zoukankan      html  css  js  c++  java
  • 吉司机线段树学习笔记

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

  • 相关阅读:
    nodejs处理get请求
    ubuntu中chromium无法播放flash,安装flash
    JQuery日历控件
    深度理解Jquery 中 offset() 方法
    javascrip中parentNode和offsetParent之间的区别
    JQuery判断元素是否存在
    javascript日历控件——纯javascript版
    canvas作为背景
    background-position控制背景位置
    javascript日历控件
  • 原文地址:https://www.cnblogs.com/Troverld/p/14620698.html
Copyright © 2011-2022 走看看