线段树的复杂操作

一,线段树做区间乘法

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

一般的话会开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
然后
暴力一波

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

原文地址:https://www.cnblogs.com/adelalove/p/11779177.html