【線段樹】加法、乘法標記加持的線段樹
阿新 • • 發佈:2019-03-07
tps == pac 更新 初始 ++ amp roo space
題目鏈接
#include<bits/stdc++.h> #define MAXN 100005 #define mid ((l+r)>>1) using namespace std; int n,m,mod,flag,x,y,z; long long a[MAXN]; struct tree { long long v,mul,add; //數據,乘法懶標,加法懶標 }t[4*MAXN]; void build(int root,int l,int r) { t[root].add=0; t[root].mul=1;//初始化懶標 if (l==r) t[root].v=a[l]; else { build(root<<1,l,mid); build(root<<1|1,mid+1,r); t[root].v=t[root<<1].v+t[root<<1|1].v; } t[root].v%=mod; return; }//初始化建樹 void pushdown(int root,int l,int r)//標記下放 { t[root<<1].v=(t[root<<1].v*t[root].mul+t[root].add*(mid-l+1))%mod; t[root<<1|1].v=(t[root<<1|1].v*t[root].mul+t[root].add*(r-mid))%mod;//更新值 t[root<<1].add=(t[root<<1].add*t[root].mul+t[root].add)%mod;//左兒子的加法標記 t[root<<1|1].add=(t[root<<1|1].add*t[root].mul+t[root].add)%mod;//右兒子的加法標記 t[root<<1].mul=(t[root<<1].mul*t[root].mul)%mod;//左兒子的乘法標記 t[root<<1|1].mul=(t[root<<1|1].mul*t[root].mul)%mod;//右兒子的乘法標記 t[root].add=0;t[root].mul=1;//清空標記 } void addition(int root,int now_l,int now_r,int l,int r,long long k) { if(l>now_r||r<now_l) return;//無重疊部分 if(l<=now_l&&r>=now_r)//部分重疊 { t[root].add=(t[root].add+k)%mod;//修改加法標記 t[root].v=(t[root].v+k*(now_r-now_l+1))%mod;//修改當前點 return; } pushdown(root,now_l,now_r); int Mid=(now_l+now_r)>>1; addition(root<<1,now_l,Mid,l,r,k); addition(root<<1|1,Mid+1,now_r,l,r,k); //二分進行加法操作 t[root].v=(t[root<<1].v+t[root<<1|1].v)%mod; return; } void multiplication(int root,int now_l,int now_r,int l,int r,long long k) { if(l>now_r||r<now_l) return;//無重疊部分 if(l<=now_l&&r>=now_r)//部分重疊 { t[root].v=(t[root].v*k)%mod;//修改當前點 t[root].add=(t[root].add*k)%mod;//修改加法標記 t[root].mul=(t[root].mul*k)%mod;//修改乘法標記 return; } pushdown(root,now_l,now_r); int Mid=(now_l+now_r)>>1; multiplication(root<<1,now_l,Mid,l,r,k); multiplication(root<<1|1,Mid+1,now_r,l,r,k); //二分進行乘法操作 t[root].v=(t[root<<1].v+t[root<<1|1].v)%mod; return; } long long query(int root,int now_l,int now_r,int l,int r) { if(l>now_r||r<now_l) return 0;//無重疊部分 if(l<=now_l&&r>=now_r) return t[root].v;//部分重疊 pushdown(root,now_l,now_r); int Mid=(now_l+now_r)>>1; return (query(root<<1,now_l,Mid,l,r)+query(root<<1|1,Mid+1,now_r,l,r))%mod; } template<class T> inline void read(T &re) { re=0;T sign=1;char tmp; while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;re=tmp-'0'; while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=re*10+(tmp-'0');re*=sign; } int main() { read(n);read(m);read(mod); for(register int i=1;i<=n;i++) read(a[i]); build(1,1,n); for(register int i=1;i<=m;i++) { read(flag); if(flag==1) {read(x);read(y);read(z);multiplication(1,1,n,x,y,z);} else if(flag==2){read(x);read(y);read(z);addition(1,1,n,x,y,z);} else if(flag==3){read(x);read(y);printf("%lld\n",query(1,1,n,x,y));} } return 0; }
【線段樹】加法、乘法標記加持的線段樹