线段树(标记下传乘法和加法)
Posted 1129-tangqiyuan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树(标记下传乘法和加法)相关的知识,希望对你有一定的参考价值。
传送门:https://www.luogu.org/problem/P3373
标记下传,这种东西就是在求和和更改的时候进行pushdown把标记(各种标记,类似于寒冰标记、痛苦标记、穹妹标记……)下传,来节省时间。
还是挺简单的,主要问题处在pushdown上但多看看就会了
#include<bits/stdc++.h> using namespace std; long long n,m,p; long long multag[1000009]; long long addtag[1000009]; long long seg[4000009]; long long num[1000009]; inline long long kd() { long long x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+(ch^48);ch=getchar();} return x*f; } inline long long ls(long long x){return x<<1;} inline long long rs(long long x){return x<<1|1;} void build(long long now,long long l,long long r) { addtag[now]=0; multag[now]=1; if(l==r) { seg[now]=num[l]%p; return; } long long mid=(l+r)>>1; build(ls(now),l,mid); build(rs(now),mid+1,r); seg[now]=(seg[ls(now)]+seg[rs(now)])%p; return; } void pushdown(long long now,long long l,long long r) { long long mid=(l+r)>>1; seg[ls(now)]=(seg[ls(now)]*multag[now]+addtag[now]*(mid-l+1))%p; seg[rs(now)]=(seg[rs(now)]*multag[now]+addtag[now]*(r-mid))%p; multag[ls(now)]=(multag[ls(now)]*multag[now])%p; multag[rs(now)]=(multag[rs(now)]*multag[now])%p; addtag[ls(now)]=(addtag[ls(now)]*multag[now]+addtag[now])%p; addtag[rs(now)]=(addtag[rs(now)]*multag[now]+addtag[now])%p; multag[now]=1; addtag[now]=0; } void mulchange(long long now,long long l,long long r,long long a,long long b,long long c) { if(r<a||l>b)return; if(a<=l&&r<=b) { seg[now]=(seg[now]*c)%p; multag[now]=(multag[now]*c)%p; addtag[now]=(addtag[now]*c)%p; return; } pushdown(now,l,r); long long mid=(l+r)>>1; mulchange(ls(now),l,mid,a,b,c); mulchange(rs(now),mid+1,r,a,b,c); seg[now]=(seg[ls(now)]+seg[rs(now)])%p; return; } void addchange(long long now,long long l,long long r,long long a,long long b,long long c) { if(r<a||l>b)return; if(l>=a&&r<=b) { addtag[now]=(addtag[now]+c)%p; seg[now]=(seg[now]+c*(r-l+1))%p; return; } pushdown(now,l,r); long long mid=(l+r)>>1; addchange(ls(now),l,mid,a,b,c); addchange(rs(now),mid+1,r,a,b,c); seg[now]=(seg[ls(now)]+seg[rs(now)])%p; return; } long long query(long long now,long long l,long long r,long long a,long long b) { if(r<a||l>b)return 0; if(l>=a&&r<=b)return seg[now]; pushdown(now,l,r); long long mid=(l+r)>>1; return (query(ls(now),l,mid,a,b)+query(rs(now),mid+1,r,a,b))%p; } int main() { n=kd(),m=kd(),p=kd(); for(register int i=1;i<=n;i++) { num[i]=kd(); } build(1,1,n); for(int i=1;i<=m;i++) { long long pan=kd(); long long a=kd(),b=kd(); if(pan==1) { long long c=kd(); mulchange(1,1,n,a,b,c); } if(pan==2) { long long c=kd(); addchange(1,1,n,a,b,c); } if(pan==3) { cout<<query(1,1,n,a,b)<<endl; } } return 0; }
以上是关于线段树(标记下传乘法和加法)的主要内容,如果未能解决你的问题,请参考以下文章
P2023 [AHOI2009]维护序列 - 线段树区间乘法加法