bzoj 1798: [Ahoi2009]Seq 维护序列seq (线段树)
2017-03-26 18:57
447 查看
题目描述
传送门
题目大意:有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值题解
线段树维护加乘标记的裸题。。。代码
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 400003 #define LL long long using namespace std; int n,m,a ; LL tr ,add ,mul ,p; void update(int x) { tr[x]=(tr[x<<1]+tr[x<<1|1])%p; } void build(int now,int l,int r) { mul[now]=1; add[now]=0; if (l==r) { tr[now]=a[l]; mul[now]=1; return; } int mid=(l+r)/2; build(now<<1,l,mid); build(now<<1|1,mid+1,r); update(now); } void pushdown(int now,int l,int r) { int mid=(l+r)/2; if (mul[now]!=1) { tr[now<<1]=tr[now<<1]*mul[now]%p; tr[now<<1|1]=tr[now<<1|1]*mul[now]%p; mul[now<<1]=mul[now<<1]*mul[now]%p; mul[now<<1|1]=mul[now<<1|1]*mul[now]%p; add[now<<1]=add[now<<1]*mul[now]%p; add[now<<1|1]=add[now<<1|1]*mul[now]%p; mul[now]=1; } if (add[now]) { tr[now<<1]+=add[now]*(mid-l+1)%p; if (tr[now]>=p) tr[now]-=p; tr[now<<1|1]+=add[now]*(r-mid)%p; if (tr[now]>=p) tr[now]-=p; add[now<<1]+=add[now]; if (add[now]>=p) add[now]-=p; add[now<<1|1]+=add[now]; if (add[now]>=p) add[now]-=p; add[now]=0; } } void qjmul(int now,int l,int r,int ll,int rr,LL val) { if (ll<=l&&r<=rr) { tr[now]=tr[now]*val%p; mul[now]=mul[now]*val%p; add[now]=add[now]*val%p; return; } int mid=(l+r)/2; pushdown(now,l,r); if (ll<=mid) qjmul(now<<1,l,mid,ll,rr,val); if (rr>mid) qjmul(now<<1|1,mid+1,r,ll,rr,val); update(now); } void qjadd(int now,int l,int r,int ll,int rr,LL val) { if (ll<=l&&r<=rr) { tr[now]=(LL)(tr[now]+(LL)(r-l+1)*val%p); if (tr[now]>=p) tr[now]-=p; add[now]+=val; if (add[now]>=p) add[now]-=p; return; } int mid=(l+r)/2; pushdown(now,l,r); if (ll<=mid) qjadd(now<<1,l,mid,ll,rr,val); if (rr>mid) qjadd(now<<1|1,mid+1,r,ll,rr,val); update(now); //cout<<l<<" "<<r<<" "<<tr[now]<<endl; } LL qjsum(int now,int l,int r,int ll,int rr) { if (ll<=l&&r<=rr) return tr[now]; int mid=(l+r)/2; LL ans=0; pushdown(now,l,r); if (ll<=mid) ans+=qjsum(now<<1,l,mid,ll,rr); ans%=p; if (rr>mid) ans+=qjsum(now<<1|1,mid+1,r,ll,rr); ans%=p; return ans; } int main() { freopen("a.in","r",stdin); //freopen("my.out","w",stdout); scanf("%d%lld",&n,&p); for (int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); scanf("%d",&m); for (int i=1;i<=m;i++) { int opt,x,y,z; scanf("%d%d%d",&opt,&x,&y); if (opt==2) { scanf("%d",&z); qjadd(1,1,n,x,y,z); // cout<<tr[1]<<endl; } if (opt==1) { scanf("%d",&z); qjmul(1,1,n,x,y,z); } if (opt==3) { printf("%lld\n",qjsum(1,1,n,x,y)%p); } } }
相关文章推荐
- 【我可能学了假线段树】【线段树】BZOJ1798 [AHOI2009]Seq 维护序列seq
- bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树)
- 线段树 BZOJ1798 [Ahoi2009]Seq 维护序列seq
- BZOJ1798:[Ahoi2009]Seq 维护序列 线段树
- 【BZOJ1798】【Ahoi2009】维护序列seq(线段树)
- BZOJ 1798 [Ahoi2009]Seq 维护序列seq 线段树
- bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq( 线段树 )
- BZOJ - 1798: [Ahoi2009]Seq 维护序列seq (线段树 区间更新)
- 【BZOJ】1798: [Ahoi2009]Seq 维护序列seq(线段树)
- Bzoj 1798: [Ahoi2009]Seq 维护序列seq(线段树区间操作)
- bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和
- BZOJ 1798 [Ahoi2009]Seq 维护序列seq 线段树模板
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq (线段树乘法加法的混合操作)
- BZOJ 1798 [Ahoi2009]Seq 维护序列seq 线段树
- 【bzoj1798】[Ahoi2009]Seq 维护序列seq 线段树
- bzoj1798 [Ahoi2009]Seq 维护序列seq 线段树
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq 线段树题解
- bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树)
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq (线段树乘法加法的混合操作)