一,线段树做区间乘法
首先要明白,乘法操作高于加法操作
一般的话会开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 }
二,区间除法,开方操作
除法,开方的操作会让各个数字之间越来越相近,最后变成一串一串连续的数字都是一样的,所以对于这一部分的操作我们一定程度上使用暴力,而如果一段都相等就相当于直接进行区间减法的操作
(对于单个点或者区间内的数完全相同的区间,可以做成区间减法
因为除法会使数变小,而相同的数减小的量是相同的)
那么我们来看如何判断区间一段都相等,那我们只需要维护区间的最值,最小值==最大值就完全相等了
1除法不能打lazy而是更新到底,复杂度可以保证(log级别),因为很快降到0
然后
暴力一波
代码,见相关的题解,我的
原文地址:https://www.cnblogs.com/adelalove/p/11779177.html
时间: 2024-10-12 18:12:39