BZOJ 1798-维护序列seq(线段树区间更新)

来源:互联网 发布:电脑视频录像软件 编辑:程序博客网 时间:2024/05/16 13:38

1798: [Ahoi2009]Seq 维护序列seq

Time Limit: 30 Sec  Memory Limit: 64 MB
Submit: 6582  Solved: 2345
[Submit][Status][Discuss]

Description

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。

Input

第一行两个整数N和P(1≤P≤1000000000)。第二行含有N个非负整数,从左到右依次为a1,a2,…,aN, (0≤ai≤1000000000,1≤i≤N)。第三行有一个整数M,表示操作总数。从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:“1 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai×c (1≤t≤g≤N,0≤c≤1000000000)。 操作2:“2 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai+c (1≤t≤g≤N,0≤c≤1000000000)。 操作3:“3 t g”(不含双引号)。询问所有满足t≤i≤g的ai的和模P的值 (1≤t≤g≤N)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

Output

对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。

Sample Input

7 43
1 2 3 4 5 6 7
5
1 2 5 5
3 2 4
2 3 7 9
3 1 3
3 4 7

Sample Output

2
35
8

HINT


线段树区间更新模板题,唯一难点在于乘除先后顺序的处理,这里设定优先级,先乘后加(只是相对的),pushdownpushdown的时候乘法标记直接乘,加法标记先乘上父亲的乘法标记再加上父亲的加法标记


#include<map>#include<stack>#include<queue>#include<vector>#include<math.h>#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include<algorithm>using namespace std;typedef long long  ll;#define inf 10000000#define  maxn  800005#define  eps 1e-10ll sum[maxn],add[maxn],mul[maxn];void build(ll l,ll r,ll id,ll p){if(l==r){mul[id]=1;add[id]=0;scanf("%lld",&sum[id]);return;}ll m=(l+r)/2;build(l,m,id*2,p);build(m+1,r,id*2+1,p);sum[id]=(sum[id*2]+sum[id*2+1])%p;mul[id]=1;add[id]=0;}void pushdown(ll id,ll l,ll r,ll p){mul[id*2]*=mul[id];mul[id*2]%=p;mul[id*2+1]*=mul[id];mul[id*2+1]%=p;add[id*2]*=mul[id];add[id*2]%=p;add[id*2+1]*=mul[id];add[id*2+1]%=p;add[id*2]+=add[id];add[id*2]%=p;add[id*2+1]+=add[id];add[id*2+1]%=p;sum[id]=sum[id]*mul[id]+(r-l+1)*add[id];sum[id]%=p;add[id]=0;mul[id]=1;}void updata1(ll id,ll L,ll R,ll l, ll r,ll x,ll p){pushdown(id,L,R,p);if(l>R || r<L)return;if(l<=L && r>=R){add[id]+=x;pushdown(id,L,R,p);return;}ll m=(L+R)/2;//if(l<=m)updata1(id*2,L,m,l,r,x,p);//if(r>m)updata1(id*2+1,m+1,R,l,r,x,p);sum[id]=(sum[id*2]+sum[id*2+1])%p;}void updata2(ll id,ll L,ll R,ll l, ll r,ll x,ll p){pushdown(id,L,R,p);if(l>R || r<L)return;if(l<=L && r>=R){mul[id]*=x;pushdown(id,L,R,p);return;}ll m=(L+R)/2;//if(l<=m)updata2(id*2,L,m,l,r,x,p);//if(r>m)updata2(id*2+1,m+1,R,l,r,x,p);sum[id]=(sum[id*2]+sum[id*2+1])%p;}ll query(ll id,ll L,ll R,ll l,ll r,ll p){pushdown(id,L,R,p);ll ans=0;if(l>R || r<L)return 0;if(l<=L && R<=r)return sum[id]%p;ll m=(L+R)/2;//if(l<=m)ans=(ans+query(id*2,L,m,l,r,p))%p;//if(r>m)ans=(ans+query(id*2+1,m+1,R,l,r,p))%p;sum[id]=(sum[id*2]+sum[id*2+1])%p;return ans%p;}int  main(void){ll n,q,i,j,x,y,z,w,p;scanf("%lld%lld",&n,&p);build(1,n,1,p);scanf("%lld",&q);while(q--){scanf("%lld",&w);if(w==1){scanf("%lld%lld%lld",&x,&y,&z);updata2(1,1,n,x,y,z,p);}if(w==2){scanf("%lld%lld%lld",&x,&y,&z);updata1(1,1,n,x,y,z,p);}if(w==3){scanf("%lld%lld",&x,&y);printf("%lld\n",query(1,1,n,x,y,p)%p);}}return 0;}


阅读全文
0 0