ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【DS】 线段树分裂&合并学习笔记

2022-08-18 20:32:23  阅读:137  来源: 互联网

标签:val rs int 线段 tre 笔记 分裂 DS


大家好哇,我又来学数据结构了。

参考资料:

不分解的氢氧化银

模板题解

前置芝士:

  • 线段树(废话)

  • 动态开点

  • 亿点树上问题基础

线段树合并

顾名思义,我们要把两颗线段树合并在一起,如图


(假设我们要维护的是权值和的信息,维护其他信息只需要稍作更改)

实现起来很简单,我们只需要把对应位置相加起来就行了。

//稍微改了下马蜂(
void merge(int &x,int y) {
    if(!x||!y) x|=y;
    else {
        tre[x].val+=tre[y].val;
        merge(ls(x),ls(y));
        merge(rs(x),rs(y));
    }
}

为了节省空间不开新点,直接将 y 树合并到 x 树上,但这样做的前提是在之后的操作中,y 树不会再出现。因为我们直接合并的话,x 和 y 树是共用一个结点的,如果对其中一棵树有更改,会对另一棵树有影响。因此,如果 y 树合并后还会再出现,建议新开点存合并后的树。

有人问,这两次递归都调用了,时间复杂度不是 \(O(n)\) 的嘛?

不是的,是 \(O(\log n)\),证法有点玄学,窝不会(

线段树分裂

顾名思义,就是合并反过来操作。线段树的分裂,有按权值分裂和按区间分裂(怎么一股 fhq 的味道),这里依次讲解。

按权值分裂(按 \(k\) 小分裂)

void split(int x,int &y,int k) {//x为原(子)树,分裂后为前k小的树,y为剩下的树 
    y=++cnt;int val=tre[ls(x)].val;
    if(k>v) split(rs(x),rs(y),k-v);
    else swap(rs(x),rs(y));
    if(k<v) split(ls(x),ls(y),k);
    tre[y].val=tre[x].val-k;
    tre[x].val=k;
}

这里我们分情况讨论:(\(v\) 为左子树的权值/大小)

  • 当 \(v<k\) 时,左子树给 \(x\) 不用处理,直接分裂右子树。

  • 当 \(v\ge k\) 时,右边归 \(y\) ,swap 一下就行。

  • 当 \(v>k\) 时,还需要递归左边。

最后将权值赋值一下就行。

按区间分裂

很简单,像普通线段树一样,把区间剖出来就行了。

inline void pushup(int p) {tre[p].val=tre[ls(p)].val+tre[rs(p)].val;}
int split(int &p,int l,int r,int L,int R) {//l,r为原(子)树区间,L,R为剖出来的区间
    int now=++cnt;
    if(L<=l&&r<=R) {
        tre[now]=tre[p];
        p=0;return now;
    }
    int mid=l+r>>1;
    if(L<=mid) ls(now)=split(ls(p),l,mid,L,R);
    if(R>mid) rs(now)=split(rs(p),mid+1,r,L,R);
    pushup(p);pushup(now);
    return now;
}

如果原树区间被覆盖,则直接搞出来就行,把原树置为 \(0\)。

否则按普通线段树一样递归,记得更新信息。

例题

先丢上来待会写做法。

P5494 【模板】线段树分裂

P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并

P3224 [HNOI2012]永无乡

P3201 [HNOI2009] 梦幻布丁

CF600E Lomsat gelral

标签:val,rs,int,线段,tre,笔记,分裂,DS
来源: https://www.cnblogs.com/RuntimeErr/p/16599988.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有