线段树2
Posted scorpiorax
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树2相关的知识,希望对你有一定的参考价值。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 typedef long long ll; 5 const int N=1e6+5; 6 struct tree 7 { 8 int l,r; 9 ll sum,lz1,lz2; 10 }t[N]; 11 ll n,m,P; 12 ll a[N]; 13 void push_up(int p) 14 { 15 t[p].sum=(t[p<<1].sum+t[p<<1|1].sum)%P; 16 } 17 void push_down(int p) 18 { 19 if(t[p].l==t[p].r) return; 20 ll q; 21 if(t[p].lz1!=1) 22 { 23 q=t[p].lz1; 24 t[p].lz1=1; 25 t[p<<1].lz1=t[p<<1].lz1*q%P; 26 t[p<<1].lz2=t[p<<1].lz2*q%P; 27 t[p<<1|1].lz1=t[p<<1|1].lz1*q%P; 28 t[p<<1|1].lz2=t[p<<1|1].lz2*q%P; 29 t[p<<1].sum=t[p<<1].sum*q%P; 30 t[p<<1|1].sum=t[p<<1|1].sum*q%P; 31 } 32 if(t[p].lz2) 33 { 34 q=t[p].lz2; 35 t[p].lz2=0; 36 t[p<<1].lz2=(t[p<<1].lz2+q)%P; 37 t[p<<1|1].lz2=(t[p<<1|1].lz2+q)%P; 38 t[p<<1].sum=(t[p<<1].sum+(t[p<<1].r-t[p<<1].l+1)*q)%P; 39 t[p<<1|1].sum=(t[p<<1|1].sum+(t[p<<1|1].r-t[p<<1|1].l+1)*q)%P; 40 } 41 } 42 43 void build(int p,int l,int r) 44 { 45 t[p].l=l;t[p].r=r;t[p].sum=t[p].lz2=0;t[p].lz1=1; 46 if(l==r) return (void)(t[p].sum=a[l]); 47 int mid=l+r>>1; 48 build(p<<1,l,mid); 49 build(p<<1|1,mid+1,r); 50 push_up(p); 51 } 52 void modify1(int p,int l,int r,ll w) 53 { 54 if(l==t[p].l && r==t[p].r) 55 { 56 t[p].lz1=t[p].lz1*w%P; 57 t[p].lz2=t[p].lz2*w%P; 58 t[p].sum=t[p].sum*w%P; 59 return; 60 } 61 push_down(p); 62 int mid=t[p].l+t[p].r>>1; 63 if(mid>=r) modify1(p<<1,l,r,w); 64 else if(l>mid) modify1(p<<1|1,l,r,w); 65 else modify1(p<<1,l,mid,w),modify1(p<<1|1,mid+1,r,w); 66 push_up(p); 67 } 68 void modify2(int p,int l,int r,ll w) 69 { 70 if(l==t[p].l && r==t[p].r) 71 { 72 t[p].lz2=(t[p].lz2+w)%P; 73 t[p].sum=(t[p].sum+(t[p].r-t[p].l+1)*w)%P; 74 return; 75 } 76 push_down(p); 77 int mid=t[p].l+t[p].r>>1; 78 if(mid>=r) modify2(p<<1,l,r,w); 79 else if(l>mid) modify2(p<<1|1,l,r,w); 80 else modify2(p<<1,l,mid,w),modify2(p<<1|1,mid+1,r,w); 81 push_up(p); 82 } 83 ll query(int p,int l,int r) 84 { 85 // printf("%d %d %d %d %lld\n",l,r,t[p].l,t[p].r,t[p].sum); 86 if(l==t[p].l && r==t[p].r) return t[p].sum; 87 push_down(p); 88 int mid=t[p].l+t[p].r>>1; 89 90 if(mid>=r) return query(p<<1,l,r); 91 if(l>mid) return query(p<<1|1,l,r); 92 return (query(p<<1,l,mid)+query(p<<1|1,mid+1,r))%P; 93 } 94 int main() 95 { 96 scanf("%lld%lld%lld",&n,&m,&P); 97 for(int i=1;i<=n;i++) scanf("%lld",&a[i]); 98 build(1,1,n); 99 ll k; 100 for(int i=1,op,x,y;i<=m;i++) 101 { 102 // for(int i=1;i<=n;i++) printf("%d:%lld\n",i,query(1,i,i)); 103 scanf("%d",&op); 104 if(op==1)scanf("%d%d%lld",&x,&y,&k),modify1(1,x,y,k); 105 if(op==2)scanf("%d%d%lld",&x,&y,&k),modify2(1,x,y,k); 106 if(op==3)scanf("%d%d",&x,&y),printf("%lld\n",query(1,x,y)); 107 108 } 109 return 0; 110 }
题目描述
如题,已知一个数列,你需要进行下面三种操作:
1.将某区间每一个数乘上x
2.将某区间每一个数加上x
3.求出某区间每一个数的和
输入输出格式
输入格式:
第一行包含三个整数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取模所得的结果
输出格式:
输出包含若干行整数,即为所有操作3的结果。
输入输出样例
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
(数据已经过加强^_^)
样例说明:
故输出应为17、2(40 mod 38=2)
以上是关于线段树2的主要内容,如果未能解决你的问题,请参考以下文章