Luogu 3373模板线段树 2
Posted labelray
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu 3373模板线段树 2相关的知识,希望对你有一定的参考价值。
题目描述
如题,已知一个数列,你需要进行下面三种操作:
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)
#include <iostream> #include <cstdio> using namespace std; struct tree{ int l,r; long long sum,add,tim; }t[400010]; int n,m; long long a[100010],P; inline int ls (int A); inline int rs (int A); inline int mid (int L,int R); void build (int l,int r,int p); void changea (int l,int r,int p,long long v); void changet (int l,int r,int p,long long v); void spread (int p); long long ask (int l,int r,int p); int main(){ int x,y,ch; long long k; cin>>n>>m>>P; for(int i=1;i<=n;i++) cin>>a[i]; build(1,n,1); for(int i=1;i<=m;i++){ cin>>ch; if(ch==1){ cin>>x>>y>>k; changet(x,y,1,k); }if(ch==2){ cin>>x>>y>>k; changea(x,y,1,k); }if(ch==3){ cin>>x>>y; cout<<ask(x,y,1)<<endl; } } return 0; } inline int ls(int A){return A<<1;} inline int rs(int A){return (A<<1)+1;} inline int mid(int L,int R){return L+R>>1;} void build(int l,int r,int p){ t[p].tim=1; t[p].l=l; t[p].r=r; if(l==r) {t[p].sum=a[l]; return;} build(l,mid(l,r),ls(p)); build(mid(l,r)+1,r,rs(p)); t[p].sum=t[ls(p)].sum+t[rs(p)].sum; // push_up(p); } void changea(int l,int r,int p,long long v){ if(l<=t[p].l && r>=t[p].r){ t[p].sum = (t[p].sum + (t[p].r - t[p].l+1) * v) % P; t[p].add = (t[p].add + v) % P; return; } spread(p); if(l <= mid(t[p].l,t[p].r)) changea(l,r,ls(p),v); if(r > mid(t[p].l,t[p].r)) changea(l,r,rs(p),v); t[p].sum = (t[ls(p)].sum + t[rs(p)].sum) % P; } void changet(int l,int r,int p,long long v){ if(l<=t[p].l && r>=t[p].r){ t[p].sum = (t[p].sum * v) % P; t[p].add = (t[p].add * v) % P; t[p].tim = (t[p].tim * v) % P; return; } spread(p); if(l<=mid(t[p].l,t[p].r)) changet(l,r,ls(p),v); if(r>mid(t[p].l,t[p].r)) changet(l,r,rs(p),v); t[p].sum = (t[ls(p)].sum + t[rs(p)].sum) % P; } void spread(int p){ t[ls(p)].sum = (t[ls(p)].sum * t[p].tim + t[p].add * (t[ls(p)].r - t[ls(p)].l + 1)) % P; t[rs(p)].sum = (t[rs(p)].sum * t[p].tim + t[p].add * (t[rs(p)].r - t[rs(p)].l + 1)) % P; t[ls(p)].add = ((t[ls(p)].add * t[p].tim) + t[p].add) % P; t[rs(p)].add = ((t[rs(p)].add * t[p].tim) + t[p].add) % P; t[ls(p)].tim = (t[ls(p)].tim * t[p].tim) % P; t[rs(p)].tim = (t[rs(p)].tim * t[p].tim) % P; t[p].add=0,t[p].tim=1; } long long ask(int l,int r,int p){ if(l<=t[p].l && r>=t[p].r) return t[p].sum%P; spread(p); long long val=0; if(l<=mid(t[p].l,t[p].r)) val=(val+ask(l,r,ls(p)))%P; if(r>mid(t[p].l,t[p].r)) val=(val+ask(l,r,rs(p)))%P; return val%P; }
以上是关于Luogu 3373模板线段树 2的主要内容,如果未能解决你的问题,请参考以下文章