线段树

基础

建树

void build(int pos,int l,int r)
{
    if(r<l)  return;
    if(l==r){scanf("%lf",&tree[pos].sum);return;}  
    int mid=l+r>>1;
    build(pos*2,l,mid);build(pos*2+1,mid+1,r);
    tree[pos].sum=tree[pos*2].sum+tree[pos*2+1].sum;
}

区间修改

复制代码
void update(LL pos,LL l,LL r,LL ll,LL rr,LL num){
    if(ll<=l&&rr>=r){
        tree[pos].sum=tree[pos].sum*mod+(LL)x*(r-l+1);
        laz1[pos]*=mod;tree[pos].laz2=tree[pos].laz2*mod+num;
        return;
    }LL mid=(l+r)>>1;pushdown(pos,mid-l+1,r-mid);
    if(mid>=ll) update(pos<<1,l,mid,ll,rr,num);
    if(mid<rr) update(pos<<1|1,mid+1,r,ll,rr,num);
    tree[pos].sum=tree[pos<<1].sum+tree[pos<<1|1].sum;
}
复制代码

懒标记(乘+加)

复制代码
void pushdown(LL pos,LL len1,LL len2){
    if(tree[pos].laz2){
        laz1[pos<<1]*=laz1[pos];
        laz1[pos<<1|1]*=laz1[pos];
        tree[pos<<1].laz2=tree[pos<<1].laz2*laz1[pos]+tree[pos].laz2;
        tree[pos<<1|1].laz2=tree[pos<<1|1].laz2*laz1[pos]+tree[pos].laz2;
        tree[pos<<1].sum=tree[pos<<1].sum*laz1[pos]+tree[pos].laz2*len1;
        tree[pos<<1|1].sum=tree[pos<<1|1].sum*laz1[pos]+tree[pos].laz2*len2;
        laz1[pos]=1;tree[pos].laz2=0;
    }
}
View Code
复制代码

(更改)

复制代码
void pushdown(LL pos,LL l1,LL l2){
    if(tree[pos].laz){
        tree[pos<<1].laz=tree[pos].laz;
        tree[pos<<1|1].laz=tree[pos].laz;
        tree[pos<<1].sum=l1*tree[pos].laz;
        tree[pos<<1|1].sum=tree[pos].laz*l2;
        tree[pos].laz=0;
    }
}
View Code
复制代码

查询(区间)

复制代码
double query(long long pos,long long l,long long r,long long ll,long long rr)
{
    if(l>rr||r<ll)  return 0;
    if(ll<=l&&r<=rr)  return tree[pos].sum;
    long long mid=(l+r)>>1;
    pushdown(pos,mid-l+1,r-mid);
    return  query(pos*2,l,mid,ll,rr)+query(pos*2+1,mid+1,r,ll,rr);
}
View Code
复制代码

 (单点)

int query(int pos,int l,int r,int x){
    if(l==r)  return t[pos].sum;
    int mid=(l+r)>>1;
    if(mid>=x)  return query(t[pos].ls,l,mid,x);
    else  return query(t[pos].rs,mid+1,r,x);
}

进阶

合并

复制代码
int merge(int ra,int rb,int l,int r){
    if(!ra) return rb;
    if(!rb) return ra;
    if(l==r){
        tree[ra].sum1+=tree[rb].sum1;
        tree[ra].sum2+=tree[rb].sum2;
        tree[ra].sum3+=tree[rb].sum3;
        return ra;
    }
    int mid=(l+r)>>1;
    ls(ra)=merge(ls(ra),ls(rb),l,mid);
    rs(ra)=merge(rs(ra),rs(rb),mid+1,r);
    pushup(ra);return ra;
}
View Code
复制代码

吉司机

将区间对x取min,单点查询

mx区间最大值,ma区间次大值,siz区间内最大值个数(暂时不用)

1.对区间内mx<x不修改,ma<x<=mx修改mx放下标记

2.ma>=x继续递归,直到1情况

复制代码
void update(int pos,int l,int r,int x,int v){
    if(x>=r){
        if(t[pos].mx<x)  return;
        if(t[pos].ma<x){
            t[pos].mx=t[pos].laz=v;return;
        }
    }int mid=l+r>>1;pushdown(pos);
    update(pos<<1,l,mid,x,v);
    if(x>mid)  update(pos<<1|1,mid+1,r,x,v);
    pushup(pos);
}int query(int pos,int l,int r,int x){
    if(l==r)  return t[pos].mx;
    int mid=l+r>>1;pushdown(pos);
    if(x<=mid)  return query(pos<<1,l,mid,x);
    else  return query(pos<<1|1,mid+1,r,x);
}void pushup(int pos){
    if(t[pos<<1].mx==t[pos<<1|1].mx){
        t[pos].mx=t[pos<<1].mx;t[pos].siz=t[pos<<1].siz+t[pos<<1|1].siz;
        t[pos].ma=max(t[pos<<1].ma,t[pos<<1|1].ma);return;
    }if(t[pos<<1].mx>t[pos<<1|1].mx){
        t[pos].mx=t[pos<<1].mx;t[pos].siz=t[pos<<1].siz;
        t[pos].ma=max(t[pos<<1].ma,t[pos<<1|1].mx);return;
    }t[pos].mx=t[pos<<1|1].mx;t[pos].siz=t[pos<<1|1].siz;
    t[pos].ma=max(t[pos<<1|1].ma,t[pos<<1].mx);
}void pushdown(int pos){
    if(t[pos].laz){
        int l1=t[pos<<1].mx;
        if(t[pos<<1].mx>=t[pos<<1|1].mx){
            t[pos<<1].mx=t[pos<<1].laz=t[pos].laz;
        }if(t[pos<<1|1].mx>=l1){
            t[pos<<1|1].mx=t[pos<<1|1].laz=t[pos].laz;
        }t[pos].laz=0;    
    }
}
View Code
复制代码

O(mlogn)时间复杂度分析(简单理解因为学长是这样讲的

1是普通线段树的时间

2将分散块集成整块,1情况增多

例如对于数列 12 21 3 5 6 9 2

极限情况对2取min  nlogn  

2 2 2 2 2 2

对1取min  O(1)

mx=2,ma=0 放下标记就跑

 

posted @   yisiwunian  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示