线段树(加法和乘法的模板)
来源:互联网 发布:网络打假举报电话是 编辑:程序博客网 时间:2024/05/16 20:46
所有的操作都没什么很大的变化
我们处理加法和乘法的时候,默认乘法操作优先于加法操作
在计算一个结点的值的时候:
val=val*mul+len*add
mul:乘法标记
len:区间长度
add:加法标记
在下传标记的时候,
儿子的值我们也是按照上面那样算
注意,标记代表的是对当前结点已经进行过的操作,但是还没有对儿子进行过该操作
整个算法中,最难的就是儿子的标记维护
child.mul=child.mul*fa.mul
child.add=child.add*fa.mul+fa.add
- 儿子节点的add标记分别先乘上父亲节点的乘标记再加上父亲节点的加标记
(因为父亲节点的加标记已经乘上了一些乘标记了,不需要再乘一次) - 儿子节点的乘标记直接乘上父亲节点的乘标记。
tip
开ll
随时%
mul标记的初始值是1,add标记初始值是0
在修改值的时候,add的维护需要累加,mul的维护需要累乘
//这里写代码片#include<cstdio>#include<cstring>#include<iostream>#define ll long longusing namespace std;const int N=100010;struct node{ int x,y; ll v,mul,ad;};node t[N<<2];int n,m;ll a[N],p;void update(int bh){ t[bh].v=t[bh<<1].v+t[(bh<<1)+1].v; t[bh].v%=p;}void push(int bh) //默认乘操作在加操作之前 { int lc=bh<<1; int rc=(bh<<1)+1; if (t[bh].mul!=1||t[bh].ad!=0) { t[lc].v=( (t[lc].v*t[bh].mul)%p + ((t[lc].y-t[lc].x+1)*t[bh].ad)%p )%p; t[lc].mul=(t[bh].mul*t[lc].mul)%p; t[lc].ad=(t[lc].ad*t[bh].mul)%p+t[bh].ad; t[lc].ad%=p; t[rc].v=( (t[rc].v*t[bh].mul)%p + ((t[rc].y-t[rc].x+1)*t[bh].ad)%p )%p; t[rc].mul=(t[bh].mul*t[rc].mul)%p; t[rc].ad=(t[rc].ad*t[bh].mul)%p+t[bh].ad; t[rc].ad%=p; t[bh].ad=0; t[bh].mul=1; } return;}void build(int bh,int l,int r){ t[bh].x=l; t[bh].y=r; t[bh].mul=1; t[bh].ad=0; if (l==r) { t[bh].v=a[l]%p; return; } int mid=(l+r)>>1; build(bh<<1,l,mid); build(bh<<1|1,mid+1,r); update(bh);}void add(int bh,int l,int r,ll val){ push(bh); if (t[bh].x>=l&&t[bh].y<=r) { t[bh].ad+=val; t[bh].ad%=p; t[bh].v=( t[bh].v*t[bh].mul%p + ((t[bh].y-t[bh].x+1)*t[bh].ad)%p )%p; return; } int mid=(t[bh].x+t[bh].y)>>1; if (l<=mid) add(bh<<1,l,r,val); if (r>mid) add((bh<<1)+1,l,r,val); update(bh);}void multi(int bh,int l,int r,ll val){ push(bh); if (t[bh].x>=l&&t[bh].y<=r) { t[bh].mul*=val; t[bh].mul%=p; t[bh].v=( t[bh].v*t[bh].mul%p + ((t[bh].y-t[bh].x+1)*t[bh].ad)%p )%p; return; } int mid=(t[bh].x+t[bh].y)>>1; if (l<=mid) multi(bh<<1,l,r,val); if (r>mid) multi((bh<<1)+1,l,r,val); update(bh);}int ask(int bh,int l,int r){ push(bh); if (t[bh].x>=l&&t[bh].y<=r) return t[bh].v%p; ll ans=0; int mid=(t[bh].x+t[bh].y)>>1; if (l<=mid) ans+=ask(bh<<1,l,r); if (r>mid) ans+=ask((bh<<1)+1,l,r); return ans%p;}int main(){ scanf("%d%d%lld",&n,&m,&p); for (int i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,1,n); int opt,x,y; ll z; for (int i=1;i<=m;i++) { scanf("%d%d%d",&opt,&x,&y); if (opt==3){ printf("%lld\n",ask(1,x,y)%p); } else if (opt==2) { scanf("%lld",&z); add(1,x,y,z%p); } else { scanf("%lld",&z); multi(1,x,y,z%p); } } return 0;}
阅读全文
0 0
- 线段树(加法和乘法的模板)
- 线段树模板(乘法加法一起处理哦)
- 线段树多个信息的传递(加法和乘法) seq
- 【矩阵的乘法和加法模板】
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq (线段树乘法加法的混合操作)
- 大数的阶乘(乘法)及加法(详细模板)
- 大数加法和大数乘法模板函数
- 线段树区间乘法+区间加法
- 分数的加法和乘法
- 多项式的加法和乘法
- 矩阵的加法和乘法
- 大数与小数模板(乘法,加法)
- 高精度(乘法和加法)
- 大数运算之加法和乘法算法C++模板
- 计算器的加法和乘法的实现
- [jzoj]1663. 【AHOI2009】维护序列(线段树+乘法加法原理)
- 大数加法和大数乘法的实现
- python的矩阵加法和乘法
- Layout POJ
- 4. Median of Two Sorted Arrays(两个有序数组的中位数)
- Java 基础接口
- 获取开机时长与开机时间
- Python笔记Day4
- 线段树(加法和乘法的模板)
- java自定义功能去除字符串两端的空格
- 爬虫基础
- 【数据结构与算法】栈和队列 备忘
- 167. Two Sum II
- fatal error C1853 预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)
- TensorFlow学习笔记3——windows下采用Anaconda时使用tensorboard的方法
- 最新版勤哲Excel服务器V2017.13.0.1无限用户支持手机APP,微信,任意安装,支持后续升级
- unity3d url 解码 编码