博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线段树区间加乘(模板)
阅读量:5164 次
发布时间:2019-06-13

本文共 3342 字,大约阅读时间需要 11 分钟。

马上要进入暑假的训练了,所以复习了一下线段树的模板,感觉同最开始的理解又加深了一些,所以还是写博客总结一下,方便日后复习。

是一道线段树区间加乘模板(裸),今天就又敲了一遍,有几个地方是我自己觉得很重要的。

1.考虑是否要开Long Long。

2.乘的标记一开始赋为1,在标记下传后也要请为1(这个很简单,但我觉得容易忘)

3.在标记更新的时候一定要先乘后加,这个很重要。

4.乘标记更新时会对加标记造成影响,加标记更新时不会对乘标记造成影响。

void modify_c(int k,int L,int R,int l,int r,LL v){    if(L>=l&&R<=r)    {        mul[k]=mul[k]*v%p;        add[k]=add[k]*v%p;        sum[k]=sum[k]*v%p;        return;    }    pushdown(k,L,R);    int mid=(L+R)>>1;    if(l<=mid) modify_c(lc[k],L,mid,l,r,v);    if(r>mid) modify_c(rc[k],mid+1,R,l,r,v);    sum[k]=(sum[lc[k]]+sum[rc[k]])%p;}
乘标记更新

5.pushdown中更新下面的总值的时候不把要更新的点的add和mul也弄进去,因为它会在modify的时候被更新,在L>=l&&R<=r里。(具体看代码)

#include
#define LL long long#define N 100003using namespace std;int p;int ndnum=1;LL sum[N<<2],mul[N<<2],add[N<<2],lc[N<<2],rc[N<<2],a[N];int read(){ int f=1,x=0;char s=getchar(); while(s<'0'||s>'9'){
if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f;}void build(int k,int l,int r){ mul[k]=1; if(l==r) {sum[k]=a[l]%p;return;} int mid=(l+r)>>1; build(lc[k]=++ndnum,l,mid); build(rc[k]=++ndnum,mid+1,r); sum[k]=(sum[lc[k]]+sum[rc[k]])%p;}void pushdown(int k,int l,int r){ //为什么在pushdown中更新下面的总值的时候为什么不把要更新的点的mul也乘进去, //是因为在modify的时候我已经用他原来的mul值更新过一遍了,当然不需要乘进去 //add同理 //为什么要把mul的值和add的值又更新到要更新的点的mul和add上呢? //这个则是因为后面又要pushdown的时候,一定要连着这个一起pushdown下去。 mul[lc[k]]=mul[lc[k]]*mul[k]%p; mul[rc[k]]=mul[rc[k]]*mul[k]%p; add[lc[k]]=add[lc[k]]*mul[k]%p; add[rc[k]]=add[rc[k]]*mul[k]%p; add[lc[k]]=(add[lc[k]]+add[k])%p; add[rc[k]]=(add[rc[k]]+add[k])%p; int mid=(l+r)>>1; sum[lc[k]]=sum[lc[k]]*mul[k]%p; sum[rc[k]]=sum[rc[k]]*mul[k]%p; sum[lc[k]]=(sum[lc[k]]+add[k]*(mid-l+1)%p)%p; sum[rc[k]]=(sum[rc[k]]+add[k]*(r-mid)%p)%p; add[k]=0;mul[k]=1;}void modify_add(int k,int L,int R,int l,int r,LL v){ if(L>=l&&R<=r) { add[k]=(add[k]+v)%p; sum[k]=(sum[k]+(R-L+1)*v)%p; return; } pushdown(k,L,R); int mid=(L+R)>>1; if(l<=mid)modify_add(lc[k],L,mid,l,r,v); if(r>mid)modify_add(rc[k],mid+1,R,l,r,v); sum[k]=(sum[lc[k]]+sum[rc[k]])%p;}void modify_c(int k,int L,int R,int l,int r,LL v){ if(L>=l&&R<=r) { mul[k]=mul[k]*v%p; add[k]=add[k]*v%p; sum[k]=sum[k]*v%p;//就是在这里,已经用他原来的mul值更新过一遍了,所以在pushdown的时候sum[lc[k]]是乘加mul[k]和add[k] return; } pushdown(k,L,R); int mid=(L+R)>>1; if(l<=mid) modify_c(lc[k],L,mid,l,r,v); if(r>mid) modify_c(rc[k],mid+1,R,l,r,v); sum[k]=(sum[lc[k]]+sum[rc[k]])%p;}LL query(int k,int L,int R,int l,int r){ if(L>=l&&R<=r) return sum[k]; int mid=(L+R)>>1; pushdown(k,L,R); LL ans=0; if(l<=mid) ans=(ans+query(lc[k],L,mid,l,r))%p; if(r>mid) ans=(ans+query(rc[k],mid+1,R,l,r))%p; return ans%p;}int main(){ int n=read(),m=read();p=read(); for(int i=1;i<=n;++i) a[i]=read(); build(1,1,n); for(int i=1;i<=m;++i) { int op=read(),x=read(),y=read(); if(op==1) { LL k=read(); modify_c(1,1,n,x,y,k); } if(op==2) { LL k=read(); modify_add(1,1,n,x,y,k); } if(op==3) printf("%lld\n",query(1,1,n,x,y)); }}
洛谷3373

让我很无语的是调了好久样例过不了,最后发现是没有在main里写build。。。天,我是什么神仙。

转载于:https://www.cnblogs.com/yyys-/p/11143231.html

你可能感兴趣的文章
Filter in Servlet
查看>>
HDU4662(SummerTrainingDay03-B)
查看>>
JavaScript基础——定义变量
查看>>
MySql避免重复插入记录
查看>>
Linux--SquashFS
查看>>
Application Pool Identities
查看>>
Nginx服务编译安装、日志功能、状态模块及访问认证模式实操
查看>>
2017-3-24 开通博客园
查看>>
【MySQL性能优化】MySQL常见SQL错误用法
查看>>
3.6 字符串
查看>>
Vue2全家桶之一:vue-cli(vue脚手架)超详细教程
查看>>
nginx负载均衡 ->Tomcat8集群 -> sentinel集群 -> redis3主从
查看>>
java中static使用之静态方法注意点
查看>>
方格取数
查看>>
Struts 2 常用技术
查看>>
Mariadb/Mysql 主从复制(1)
查看>>
linux 修改ssh端口号
查看>>
Android-Layer list
查看>>
Java语言中的访问权限修饰符
查看>>
iOS9新特性之常见关键字
查看>>