• 线段树的复杂操作


    一,线段树做区间乘法

    首先要明白,乘法操作高于加法操作

    一般的话会开long long ,要去模

    对于一个节点o,我们设区间和为sum[o],加法标记为add[o],乘法标记为mul[o]

    mul标记的初始值是1,add标记初始值是0 
    在修改值的时候,add的维护需要累加,mul的维护需要累乘

    此时当我们进行区间加的时候,一切照旧

    但是当进行区间乘法的时候

    儿子节点的add标记分别先乘上父亲节点的乘标记再加上父亲节点的加标记 
    (因为父亲节点的加标记已经乘上了一些乘标记了,不需要再乘一次)

    儿子节点的乘标记直接乘上父亲节点的乘标记。

     1 void Mul(ll o,ll l,ll r,ll x,ll y,ll k)
     2 {
     3     if(x<=l && y>=r)
     4     {
     5         add[o]=add[o]%mod*k%mod;//相当于加了k个add[o]
     6         sum[o]=sum[o]*k%mod%mod;
     7         mul[o]=mul[o]*k%mod;
     8         return;
     9     }
    10     ll mid=(l+r)>>1;
    11     down(o,l,r,mid);
    12     if(x<=mid) Mul(o<<1,l,mid,x,y,k);
    13     if(y>=mid+1) Mul(o<<1|1,mid+1,r,x,y,k);
    14     sum[o]=(sum[o<<1]+sum[o<<1|1])%mod;
    15 }

    所以标记下放的时候

     1 void down(ll o,ll l,ll r,ll mid)
     2 {
     3     if(add[o]==0 && mul[o]==1) return;
     4     add[o<<1]=(add[o<<1]*mul[o]+add[o])%mod;
     5     mul[o<<1]=mul[o<<1]*mul[o]%mod;
     6     sum[o<<1]=(sum[o<<1]*mul[o]%mod+add[o]*(mid-l+1)%mod)%mod;
     7     
     8     add[o<<1|1]=(add[o<<1|1]*mul[o]+add[o])%mod;
     9     mul[o<<1|1]=mul[o<<1|1]*mul[o]%mod;
    10     sum[o<<1|1]=(sum[o<<1|1]*mul[o]+add[o]*(r-(mid+1)+1))%mod;
    11     
    12     add[o]=0;mul[o]=1;
    13 }
    View Code

    二,区间除法,开方操作

    除法,开方的操作会让各个数字之间越来越相近,最后变成一串一串连续的数字都是一样的,所以对于这一部分的操作我们一定程度上使用暴力,而如果一段都相等就相当于直接进行区间减法的操作
    (对于单个点或者区间内的数完全相同的区间,可以做成区间减法
    因为除法会使数变小,而相同的数减小的量是相同的)
    那么我们来看如何判断区间一段都相等,那我们只需要维护区间的最值,最小值==最大值就完全相等了
    1除法不能打lazy而是更新到底,复杂度可以保证(log级别),因为很快降到0
    然后
    暴力一波

    代码,见相关的题解,我的

  • 相关阅读:
    Docker 安装各种环境
    N级树形菜单封装
    一个周期算出所有高电平的个数
    DDR3新版(3):DDR3自动读写控制器
    DDR3_新版(2):IP核再封装
    数电(6):时序逻辑电路
    Vue表单那些事
    liunx环境修改minio默认端口和后台启动
    liunx 后台启动mongodb服务
    liunx安装和部署nacos配置中心
  • 原文地址:https://www.cnblogs.com/adelalove/p/11779177.html
Copyright © 2020-2023  润新知