吉司机线段树(segment tree beats!)

sdoir1考挂,本来都要退役了。。。结果还是进了二轮末尾。。。打算混个D类去养老;

最近有点颓,需要写些东西和学些新东西止一下颓势,就先把这几星期前学的神奇线段树写了吧。。。

吉司机线段树主要是用来解决序列区间上满足部分满足一定性质的修改操作的,比方说把区间中小于x的数改成x,大于x的数改成x,甚至是区间取并和区间取或(实际上也就是区间中的每个数的每一位进行类似小于x改成x那种操作)

这玩意的复杂的是很玄学的,好像要用到势能分析一类的;不过正常情况下复杂度最坏也就nlogn^2,可以放心用啦
两年之后补充一下,复杂度吉老师已经证明,若不进行区间加减是均摊nlogn.具体证明可从codeforces上找,在1290E的题解里有链接.

下面主要说一下怎么处理区间中把小于x 的数改成x,其他的可以类比来做;

首先要记一个中间量,也就是次小值;然后再把线段树上每一个区间的最小值及其个数记录下来;

对于每次修改,设要和x进行对比;

如果当前找到的区间的最小值>=x,那么肯定没必要再往下处理了;

如果x>最小值但x<次小值(注意x严格小于次小值)那么只需要把最小值改成x,记录的最小值的数目都不需要改,这样线段树上维护的其他信息也可以很方便的修改(例如区间和一类的信息)

如果x>=次小值,那递归处理左右子区间再合并信息回来;

算法的描述感觉大家都是千篇一律。。。实际写起来细节也挺多的,例如如果对最小值修改成x,要单独记到一个标记数组里,标记下传的顺序也需要仔细考虑;
其实我今天之所以会想到写这个,主要是在bzoj上做了一道相关的题,然后怎么都tle;
实际和别人比起来效率也没差多少。。。
那题是同时有两种操作,标记的合并上又有很多其他细节;
那么就放一下我卡常失败的代码,等bzoj换评测机了之后再去交吧。。。

时隔多年,我再来贡献一种实现比较方便的写法
这种写法综合了oi-wiki及我一个学长的写法
其实只需要记一下最值,次最值即可,不必单独为这类操作加个标记数组.
对于同时需要取min和取max的题目,不妨先说取min,此时需要对最大值进行操作.假设对区间进行对x取min的操作(大于x的改为x)
先说如何修改.
当递归到符合修改条件的节点(修改区间包含当前节点,且最大值大于x,次大值小于x)时,直接将最大值改为x即可.
再说如何下传标记.
其实直接将当前节点最大值当作修改值传给儿子就好.
因为当前节点是修改过的,所有值都小于等于x,对儿子节点所有值与 x x x 取min 其实等价于对儿子节点所有值与 当 前 节 点 最 大 值 当前节点最大值 取min,并且只要判断下儿子最大值是否需要修改即可,儿子的次大值肯定会小于当前节点最大值.
至于解决最大值和最小值数组冲突的问题,在取min操作时,只要判断一下修改前最大值是否等于最小值和次小值,最大值等于哪个就把哪个改为修改后的值.因为出现冲突只有可能当前区间的不同值个数小于2,区间只有一个值时最大值等于最小值,只有两个值时最大值等于次小值.
注意初始化时若区间只有一种数,次小值赋为极大,次大值赋为极小.
具体新的写法贴到文章最后了,虽然人丑大常数还是没过bzoj,不过我自测后正确性应该是没问题的.
两年前的老代码就不删了…

题目:bzoj 4695


#include<ctime>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long 
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1 
#define cmp(x,y,ck) (ck? x>y:x<y)
const int inf=2e9;
const int maxn=500005;
LL sum[maxn<<2];
int mv[maxn<<2][2],smv[maxn<<2][2],mvn[maxn<<2][2],a[maxn],col[maxn<<2],mcol[maxn<<2][2];
inline int MV(int x,int y,int ck){
    if((ck&&x>y)||(!ck&&x<y))return x;
    else return y;
}
inline void updata(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    for(int ck=0;ck<2;ck++)
    if(mv[rt<<1][ck]==mv[rt<<1|1][ck]){
        mv[rt][ck]=mv[rt<<1][ck];
        mvn[rt][ck]=mvn[rt<<1][ck]+mvn[rt<<1|1][ck];
        smv[rt][ck]=MV(smv[rt<<1][ck],smv[rt<<1|1][ck],ck);
    }else{
        int tp=(cmp(mv[rt<<1][ck],mv[rt<<1|1][ck],ck)^1);
        mv[rt][ck]=mv[(rt<<1)^tp][ck];
        mvn[rt][ck]=mvn[(rt<<1)^tp][ck];
        smv[rt][ck]=MV(smv[(rt<<1)^tp][ck],mv[(rt<<1|1)^tp][ck],ck);        
    }
}
inline void color(int l,int r,int rt,int v){
    sum[rt]+=(LL)(r-l+1)*v;
    mv[rt][0]+=v;
    mv[rt][1]+=v;
    col[rt]+=v;
    if(smv[rt][0]!=inf)smv[rt][0]+=v;
    if(smv[rt][1]!=-inf)smv[rt][1]+=v;
}
inline void mcolor(int rt,int ck,int v){
    if(mv[rt][ck]==mv[rt][ck^1]){
        mv[rt][ck^1]+=v;
        mcol[rt][ck^1]+=v;
    }
    if(mv[rt][ck]==smv[rt][ck^1])
        smv[rt][ck^1]+=v;
    mv[rt][ck]+=v;
    sum[rt]+=(LL)mvn[rt][ck]*v;
    mcol[rt][ck]+=v; 
}
inline void pushcol(int l,int r,int rt){
    if(col[rt]){
        int mid=(l+r)>>1;
        color(lson,col[rt]);
        color(rson,col[rt]);
        col[rt]=0;
    }
    for(int i=0;i<2;i++)if(mcol[rt][i]){
        if(mv[rt][i]==mv[rt<<1][i]+mcol[rt][i])mcolor(rt<<1,i,mcol[rt][i]);
        if(mv[rt][i]==mv[rt<<1|1][i]+mcol[rt][i])mcolor(rt<<1|1,i,mcol[rt][i]);
    }
    mcol[rt][0]=mcol[rt][1]=0;
}
inline void add(int l,int r,int rt,int nl,int nr,int v){
    if(nl<=l&&nr>=r){
        color(l,r,rt,v);
        return;
    }
    pushcol(l,r,rt);
    int mid=(l+r)>>1;
    if(nl<=mid)add(lson,nl,nr,v);
    if(nr>mid)add(rson,nl,nr,v);
    updata(rt);
}
inline void same(int l,int r,int rt,int v,int ck){
    if(!cmp(mv[rt][ck],v,ck))return;
    else if(cmp(v,smv[rt][ck],ck)){
        mcolor(rt,ck,v-mv[rt][ck]);
        return ;
    }
    pushcol(l,r,rt);
    int mid=(l+r)>>1;
    same(lson,v,ck);
    same(rson,v,ck);
    updata(rt);
}
inline void modify(int l,int r,int rt,int nl,int nr,int v,int ck){
    if(nl<=l&&nr>=r){
        same(l,r,rt,v,ck);
        return;
    }
    pushcol(l,r,rt);
    int mid=(l+r)>>1;
    if(nl<=mid)modify(lson,nl,nr,v,ck);
    if(nr>mid)modify(rson,nl,nr,v,ck);
    updata(rt);
}
inline LL querysum(int l,int r,int rt,int nl,int nr){
     
    while(!(nl<=l&&nr>=r)){
        pushcol(l,r,rt);
        int mid=(l+r)>>1;
        if(nl<=mid&&nr>mid)return querysum(lson,nl,nr)+querysum(rson,nl,nr);
        else if(nl<=mid)r=mid,rt<<=1;
        else l=mid+1,rt=rt<<1|1;
    }
    return sum[rt];
}
inline int querymv(int l,int r,int rt,int nl,int nr,int ck){
    while(!(nl<=l&&nr>=r)){
        pushcol(l,r,rt);
        int mid=(l+r)>>1;
        if(nl<=mid&&nr>mid)return MV(querymv(lson,nl,nr,ck),querymv(rson,nl,nr,ck),ck);
        else if(nl<=mid)r=mid,rt<<=1;
        else l=mid+1,rt=rt<<1|1;
    }
    return mv[rt][ck];
}
inline void build(int l,int r,int rt){
    col[rt]=mcol[rt][0]=mcol[rt][1]=0;
    if(l==r){
        mv[rt][0]=mv[rt][1]=a[l];
        mvn[rt][0]=mvn[rt][1]=1;
        smv[rt][0]=inf;
        smv[rt][1]=-inf;
        sum[rt]=(LL)a[l];
        return;
    } 
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    updata(rt);
} 
inline int read(){
    char c=getchar();
    int tv=0,ck=1; 
    while(c<'0'||c>'9'){
        if(c=='-')ck=-1; 
        c=getchar();
    } 
    while(c>='0'&&c<='9'){
        tv=(tv<<1)+(tv<<3)+c-'0';
        c=getchar(); 
    } 
    return tv*ck; 
} 
int main()
{
    int n,m;
    n=read(); 
    for(int i=1;i<=n;i++)a[i]=read();
    build(1,n,1); 
    m=read();
    for(int i=1;i<=m;i++){
        int ck=read(),nl=read(),nr=read();
        if(ck<=3){
            int tv=read();
            if(ck==1)add(1,n,1,nl,nr,tv);
            else modify(1,n,1,nl,nr,tv,ck==3); 
        }
        else if(ck==4)printf("%lld\n",querysum(1,n,1,nl,nr));
        else printf("%d\n",querymv(1,n,1,nl,nr,ck==5)); 
    } 
    return 0; 
}
//更新后的写法
#include<bits/stdc++.h>
using namespace std;
#define pr pair<int,int>
#define mk(a,b) make_pair(a,b)
#define LL long long
namespace SegmentTreeBeats{
    typedef LL T;
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1

    const T inf=1e9+7;
    const int maxn=5e5+5;
    T sum[maxn<<2],col[maxn<<2],v[maxn<<2];

    template<class cmp,T Inf>
    struct INFO{
        T mv,smv;
        int cnt;
        const static T INF=Inf;
        INFO operator + (const INFO& p)const{
            INFO ans;
            if(cmp()(mv,p.mv)){
                ans.mv=p.mv;
                ans.cnt=p.cnt;
                ans.smv=cmp()(mv,p.smv)?p.smv:mv;
            }else if(cmp()(p.mv,mv)){
                ans.mv=mv;
                ans.cnt=cnt;
                ans.smv=cmp()(smv,p.mv)?p.mv:smv;
            }else{
                ans.mv=mv;
                ans.cnt=cnt+p.cnt;
                ans.smv=cmp()(smv,p.smv)?p.smv:smv;
            }
            return ans;
        }
    };
    INFO<less<T>,-inf>Mx[maxn<<2];
    INFO<greater<T>,inf>Mn[maxn<<2];
    void updata(int rt){
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
        Mx[rt]=Mx[rt<<1]+Mx[rt<<1|1];
        Mn[rt]=Mn[rt<<1]+Mn[rt<<1|1];
    }
    void build(int l,int r,int rt){
        col[rt]=0;
        if(l==r){
            Mx[rt].mv=Mn[rt].mv=sum[rt]=v[l];
            Mx[rt].cnt=Mn[rt].cnt=1;
            Mx[rt].smv=Mx[rt].INF;
            Mn[rt].smv=Mn[rt].INF;
            return;
        }
        int mid=(l+r)>>1;
        build(lson);
        build(rson);
        updata(rt);
    }
    inline void color(int l,int r,int rt,T val){
        sum[rt]+=val*(r-l+1);
        col[rt]+=val;
        if(Mx[rt].smv!=-inf)Mx[rt].smv+=val;
        if(Mn[rt].smv!=inf)Mn[rt].smv+=val;
        Mx[rt].mv+=val,Mn[rt].mv+=val;
    }
    inline void colorToLess(int rt,T val){
        if(Mx[rt].mv<=val)return;
        sum[rt]+=(val-Mx[rt].mv)*Mx[rt].cnt;
        if(Mn[rt].smv==Mx[rt].mv)Mn[rt].smv=val;
        if(Mn[rt].mv==Mx[rt].mv)Mn[rt].mv=val;
        Mx[rt].mv=val;
    }
    inline void colorToMore(int rt,T val){
        if(Mn[rt].mv>=val)return;
        sum[rt]+=(val-Mn[rt].mv)*Mn[rt].cnt;
        if(Mx[rt].smv==Mn[rt].mv)Mx[rt].smv=val;
        if(Mx[rt].mv==Mn[rt].mv)Mx[rt].mv=val;
        Mn[rt].mv=val;
    }
    inline void pushcol(int l,int r,int rt){
        if(col[rt]){
            int mid=(l+r)>>1;
            color(lson,col[rt]);
            color(rson,col[rt]);
            col[rt]=0;
        }
        colorToLess(rt<<1,Mx[rt].mv);
        colorToLess(rt<<1|1,Mx[rt].mv);
        colorToMore(rt<<1,Mn[rt].mv);
        colorToMore(rt<<1|1,Mn[rt].mv);
    }
    void toLess(int l,int r,int rt,int nl,int nr,T val){
        if(Mx[rt].mv<=val)return;
        if(nl<=l&&nr>=r&&Mx[rt].smv<val){
            colorToLess(rt,val);
            return;
        }
        pushcol(l,r,rt);
        int mid=(l+r)>>1;
        if(nl<=mid)toLess(lson,nl,nr,val);
        if(nr>mid)toLess(rson,nl,nr,val);
        updata(rt);
    }

    void toMore(int l,int r,int rt,int nl,int nr,T val){
        if(Mn[rt].mv>=val)return;
        if(nl<=l&&nr>=r&&Mn[rt].smv>val){
            colorToMore(rt,val);
            return;
        }
        pushcol(l,r,rt);
        int mid=(l+r)>>1;
        if(nl<=mid)toMore(lson,nl,nr,val);
        if(nr>mid)toMore(rson,nl,nr,val);
        updata(rt);
    }
    void modify(int l,int r,int rt,int nl,int nr,T val){
        if(nl<=l&&nr>=r){
            color(l,r,rt,val);
            return ;
        }
        pushcol(l,r,rt);
        int mid=(l+r)>>1;
        if(nl<=mid)modify(lson,nl,nr,val);
        if(nr>mid)modify(rson,nl,nr,val);
        updata(rt);
    }

    T querySum(int l,int r,int rt,int nl,int nr){
        if(nl<=l&&nr>=r)return sum[rt];
        pushcol(l,r,rt);
        int mid=(l+r)>>1;
        T ans=0;
        if(nl<=mid)ans+=querySum(lson,nl,nr);
        if(nr>mid)ans+=querySum(rson,nl,nr);
        return ans;
    }
    T queryMx(int l,int r,int rt,int nl,int nr){
        if(nl<=l&&nr>=r)return Mx[rt].mv;
        pushcol(l,r,rt);
        int mid=(l+r)>>1;
        T ans=Mx->INF;
        if(nl<=mid)ans=max(ans,queryMx(lson,nl,nr));
        if(nr>mid)ans=max(ans,queryMx(rson,nl,nr));
        return ans;
    }
    T queryMn(int l,int r,int rt,int nl,int nr){
        if(nl<=l&&nr>=r)return Mn[rt].mv;
        pushcol(l,r,rt);
        int mid=(l+r)>>1;
        T ans=Mn->INF;
        if(nl<=mid)ans=min(ans,queryMn(lson,nl,nr));
        if(nr>mid)ans=min(ans,queryMn(rson,nl,nr));
        return ans;
    }

    #undef lson
    #undef rson
}
using namespace SegmentTreeBeats;
int main(){
  //  freopen("4695.in","r",stdin);
 //   freopen("4695.out","w",stdout);
    int n,m;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&v[i]);
    build(1,n,1);
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        int ck,l,r,val;
        scanf("%d%d%d",&ck,&l,&r);
        if(ck<=3)scanf("%d",&val);
        if(ck==1)modify(1,n,1,l,r,val);
        else if(ck==2)toMore(1,n,1,l,r,val);
        else if(ck==3)toLess(1,n,1,l,r,val);
        else if(ck==4)printf("%lld\n",querySum(1,n,1,l,r));
        else if(ck==5)printf("%lld\n",queryMx(1,n,1,l,r));
        else printf("%lld\n",queryMn(1,n,1,l,r));
    }
}

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值