线段树合并

线段树合并

用一个新的线段树(也可是原先中的一个)包含两个原线段树的信息便是线段树的合并。

由于基础的线段树son为i*2和i*2+1需4倍空间且下标无法改变的缺点,在需合并的情况下就要使用动态开点线段树。

动态开点线段树

多开一个数组son[N][2]记录每个点的儿子位置。(其实真的很简单:)

void build(int L,int R,int l,int r,int now)
{
    if(l==r)
    {
        t[now]=a[l];
        return;
    }
    int m=l+r>>1;
    if(L<m)
        son[now][0]=++tot,build(L,R,l,mid,tot);
    if(R>m)
        son[now][1]=++tot,build(L,R,mid,r,tot);
    pushup(now);
}

合并

两树维护的内容需具有可合并性才可合并,如区间和、区间最值都可以。

b树合并到a上,同时对两棵树做dfs,如果发现其中一棵缺少当前节点,就把另一棵树的连上去,否则按照规则合并。

是哪棵合并到另一棵上就取决于最后return的是哪棵数的点了。

普通线段树

两数组相加,区间和

int merge(int now1,int now2)///将2号树合并到1号上 
{
    if(!now1||!now2)return now1+now2;
    t[1][now1]+=t[2][now2];
    son[now1][0]=merge(son[now1][0],son[now2][0]);
    son[now2][0]=merge(son[now2][0],son[now2][0]);
    return now1;
}

两数组相加,线段树维护区间最大值和最大值下标

int merge(int now1,int now2,int l,int r)///将2号树合并到1号上 
{
    if(!now1||!now2)return now1+now2;
    if(l==r)
        t[now1].x+=t[now2].x;
    int m=l+r>>1;
    son[now1][0]=merge(son[now1][0],son[now2][0],l,m);
    son[now1][1]=merge(son[now1][1],son[now2][2],m+1,r);
    pushup(now1);
    return now1;
}

权值线段树

int merge(int x,int y,int l,int r)
{
if(!x||!y)return x+y; if(l==r){t[x].v=t[x].v+t[y].v;return x;} int mid=l+r>>1; t[x].l=merge(t[x].l,t[y].l,l,mid); t[x].r=merge(t[x].r,t[y].r,mid+1,r); pushup(x); return x; }

 

 

 

posted @ 2021-08-16 23:00  T_X蒻  阅读(38)  评论(0编辑  收藏  举报