线段树
来源:互联网 发布:手机我的世界js编辑器 编辑:程序博客网 时间:2024/05/29 03:23
贾比奇的博客
带lazytag的线段树模板
/*第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。接下来M行每行包含3或4个整数,表示一个操作,具体如下:操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和*/#include<iostream>#include<cstdio>using namespace std;long long m,n,x,y,k,z,b,sum[1000001],g[1000001],ans;inline long long read(){ long long x=0;char y; do { y=getchar(); } while(y<'0'||y>'9'); do { x=10*x+y-'0'; y=getchar(); } while(y<='9'&&y>='0'); return x;}void build(int rt,int l,int r){ if(l==r) { sum[rt]=read(); return; } long long m=(l+r)/2; build(rt*2,l,m); build(rt*2+1,m+1,r); sum[rt]=sum[2*rt]+sum[2*rt+1];}void pd(int rt,int l,int r){ int m=r-l+1; g[rt*2]+=g[rt]; g[rt*2+1]+=g[rt];//这个地方一定要有“+”,卡了我一上午 sum[rt*2+1]+=(m/2)*g[rt]; sum[rt*2]+=(m-(m/2))*g[rt]; g[rt]=0;}void update(long long rt,long long l,long long r){ if(l>=x&&r<=y) { g[rt]+=z; sum[rt]+=(r-l+1)*z; return; }//如果当前节点的区间在查询区间里,直接把lazytag放在这就好了 if(g[rt]) pd(rt,l,r);//如果不在,就把lazytag向下移 long long m=(l+r)/2; if(m>=x) update(rt*2,l,m); if(y>m) update(rt*2+1,m+1,r); sum[rt]=sum[rt*2]+sum[rt*2+1];//更新sum}long long q(long long rt,long long l,long long r){ int pc; if(l>=x&&r<=y) return sum[rt]; long long m=0,mm=(l+r)/2; if(y>mm) m+=q(2*rt+1,mm+1,r); if(x<=mm)m+=q(2*rt,l,mm); return m;}int main(){ cin>>n>>m; build(1,1,n);//建树 for(int i=1;i<=m;i++) { b=read(); if(b==1) { x=read();y=read();z=read(); update(1,1,n);//更新 } else { x=read();y=read(); printf("%lld\n",q(1,1,n));//询问 } }}
带乘法的线段树模板
只是加了一个乘法数组
每次更新时,乘法可以改变子节点加数和乘数
/*输入格式:第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。接下来M行每行包含3或4个整数,表示一个操作,具体如下:操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果*/#include<iostream>#include<cstdio>using namespace std;long long sum[1000001],ad[1000001],mu[10000001],n,m,k,p,pc,x,y,z;void build(int rt,int l,int r){ if(l==r) scanf("%d",&sum[rt]); else { long long mm=(l+r)/2; build(rt*2,l,mm); build(rt*2+1,mm+1,r); sum[rt]=sum[rt*2]+sum[rt*2+1]; }}void pd(int rt,int l,int r){ long long rs,ls,mm; ls=2*rt; rs=2*rt+1; mm=(l+r)/2; mu[ls]*=mu[rt]; mu[rs]*=mu[rt]; ad[ls]*=mu[rt]; ad[rs]*=mu[rt]; ad[ls]+=ad[rt]; ad[rs]+=ad[rt]; mu[ls]%=p; mu[rs]%=p; ad[ls]%=p; ad[rs]%=p; sum[ls]=(sum[ls]*mu[rt]+ad[rt]*(mm-l+1))%p; sum[rs]=(sum[rs]*mu[rt]+ad[rt]*(r-mm))%p; ad[rt]=0; mu[rt]=1;}void multi(int rt,int l,int r){ if(l>=x&&r<=y) //乘数可以改变加数和乘数 { mu[rt]*=z; ad[rt]*=z; sum[rt]*=z; mu[rt]%=p; ad[rt]%=p; sum[rt]%p; return; } pd(rt,l,r); long long mm=(l+r)/2; if(x<=mm) multi(rt*2,l,mm); if(y>mm) multi(rt*2+1,mm+1,r); sum[rt]=(sum[rt*2]+sum[rt*2+1])%p;}void add(int rt,int l,int r){ if(l>=x&&r<=y) { ad[rt]+=z; sum[rt]+=(r-l+1)*z; ad[rt]%=p; sum[rt]%=p; return; } pd(rt,l,r); long long mm=(l+r)/2; if(x<=mm) add(rt*2,l,mm); if(y>mm) add(rt*2+1,mm+1,r); sum[rt]=(sum[rt*2]+sum[rt*2+1])%p;}long long q(int rt ,int l,int r){ long long m=0;int mm=(l+r)/2; if(l>=x&&r<=y) { return sum[rt]%p; } pd(rt,l,r); if(x<=mm) m=(m+q(rt*2,l,mm))%p; if(y>mm) m=(m+q(rt*2+1,mm+1,r))%p; return m%p;}int main(){ cin>>n>>m>>p; for(int i=1;i<=2*n+3;i++) mu[i]=1; build(1,1,n); for(int i=1;i<=m;i++) { scanf("%d",&pc); if(pc==1) { scanf("%d%d%d",&x,&y,&z); multi(1,1,n); } if(pc==2) { scanf("%d%d%d",&x,&y,&z); add(1,1,n); } if(pc==3) { scanf("%d%d",&x,&y); printf("%lld\n",q(1,1,n)); } }}
阅读全文
0 0
- 线段树?线段树!
- 线段树?线段树!
- 线段_线段树
- 线段_线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- python opencv入门 轮廓的性质(19)
- XSS漏洞与SQL注入漏洞解决方案
- 小米推送点击无效的原因
- cordova build安卓apk,关于版本号的修改(可能有误,看看就好,别当真)
- 正则表达式运算符优先级
- 线段树
- Android内存泄露——全解析和处理办法
- Android动态设置margin和dp转为int
- OpenCV学习之采用金字塔方法进行图像分割
- React学习总结一 JSX
- 文章标题
- 《Python 基础教程》学习笔记——字典
- Samba服务器【Linux-shell】
- 解读spring.util包之FastByteArrayOutputStream