『权值动态开点线段树』『线段树合并算法』简单理解

本文介绍了权值线段树的概念,它适用于权值计数和操作。通过动态开点的方式降低复杂度,并展示了如何进行线段树的合并操作。文章通过两个竞赛题目实例说明了线段树合并在权值计数问题中的应用,包括在树形结构中的逆序对计算。最后提供了相关问题的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

权值线段树与动态开点

在正常的线段树中,我们总是以下表来进行线段树的操作。而权值线段树主要用于对具体的权值进行构造线段树,用于权值计数,权值操作等问题。

由于权值太大,我们不再采用完全二叉树的编号方式,使用类似于邻接表一样的存储方式,每一个节点只存储它儿子节点的编号;且只对有用区间进行开点操作,这样复杂度也是 l o g log log级别的。

例如,需要添加权值为为 4 4 4的点,而总区间是 [ 1 , 10 ] [1,10] [1,10];我们只需要开展区间 [ 1 , 10 ] , [ 1 , 5 ] , [ 4 , 5 ] , [ 4 , 4 ] [1,10],[1,5],[4,5],[4,4] [1,10],[1,5],[4,5],[4,4]即可。

代码如下:

void Build(int p,int l,int r,int x,int v)
{
   
   
    if (l == r) {
   
    t[p].ans = v; return; }
    int mid = l+r >> 1;
    if (x <= mid)  {
   
   
        if (t[p].lc == 0) t[p].lc = getnew();
        Build(t[p].lc,l,mid,x,v); 
    }
    else  {
   
   
        if (t[p].rc == 0) t[p].rc = getnew();
        Build(t[p].rc,mid+1,r,x,v); 
    }
    t[p].ans = t[t[p].lc].ans+t[t[p].rc].ans;
    return;
}
//单点修改位置x为v 动态开点

线段树合并

线段树合并所完成的操作就是:在相同区间内,对应位置相加。

我们可以使用如下方法解决:两个相同区间的节点分别为 p p p q q q,合并区间为 [ l , r ] [l,r] [l,r],若未建立则为0.

  • p p p q q q有其一为0,则另一者为根。
  • l = r l=r l=r,则累加权值,返回p。
  • 合并 p p p的左孩子和 q q q的左孩子, p p p的右孩子和 q q q的右孩子;再讲对应位置的权值相加,返回 p p p

代码如下:

int merge(int p,int q,int l,int r)
{
   
   
    if (p == 0) return q;
    if (q == 0) return p;
    if (l == r) 
    {
   
   
        t[p].ans += t[q].ans;
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值