线段树进阶—动态开点

  动态开点线段树

  阅读本篇请先学习线段树

  动态开点线段树是一类特殊的线段树,与普通的线段树不同的是,每一个节点的左右儿子不是该点编号的两倍和两倍加一,而是现加出来的。

  我们用lson[u]记录u的左儿子,rson[u]记录u的右儿子(博主不用define于是用ll[u]和rr[u]),其他就不赘述了,以下是建树的代码:

 

void build(long long u,long long l1,long long r1)
{
    l[u]=l1;
    r[u]=r1;
    if (l1==r1)
    {
        z[u]=a[l1];
        return;
    }
    cnt++;
    ll[u]=cnt;//用cnt记录点的个数
    build(ll[u],l1,(l1+r1)/2);
    cnt++;
    rr[u]=cnt;
    build(rr[u],(l1+r1)/2+1,r1);
    z[u]=z[ll[u]]+z[rr[u]];
}

 

  完整代码如下:

void xiafang(long long u)
{
    z[ll[u]]=c[u]*(r[ll[u]]-l[ll[u]]+1);
    c[ll[u]]+=c[u];
    z[rr[u]]=c[u]*(r[rr[u]]-l[rr[u]]+1);
    c[rr[u]]+=c[u];
    c[u]=0;
}
void build(long long u,long long l1,long long r1)
{
    l[u]=l1;
    r[u]=r1;
    if (l1==r1)
    {
        z[u]=a[l1];
        return;
    }
    cnt++;
    ll[u]=cnt;
    build(ll[u],l1,(l1+r1)/2);
    cnt++;
    rr[u]=cnt;
    build(rr[u],(l1+r1)/2+1,r1);
    z[u]=z[ll[u]]+z[rr[u]];
}
void jia(long long u,long long l1,long long r1,long long k)
{
        if (l[u]>r1||r[u]<l1) return;
    if (l[u]>=l1&&r[u]<=r1)
    {
        z[u]+=k*(r[u]-l[u]+1);
        c[u]+=k;
        return;
    }
    if (c[u]) xiafang(u);
    jia(ll[u],l1,r1,k);
    jia(rr[u],l1,r1,k);
    z[u]=z[ll[u]]+z[rr[u]];
}
long long qui(long long u,long long l1,long long r1)
{
    if (l[u]>r1||r[u]<l1) return 0;
    if (l[u]>=l1&&r[u]<=r1) return z[u];
    if (c[u]) xiafang(u);
    return (qui(ll[u],l1,r1)+qui(rr[u],l1,r1))%998244353;
}  

  其实只要将u*2和u*2+1与ll[u],rr[u]换一下其实就好了。

 

转载于:https://www.cnblogs.com/szbszb/p/11309369.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值