[Ahoi2009]Seq 维护序列seq
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
【样例说明】
初始时数列为(1,2,3,4,5,6,7)。
经过第1次操作后,数列为(1,10,15,20,25,6,7)。
对第2次操作,和为10+15+20=45,模43的结果是2。
经过第3次操作后,数列为(1,10,24,29,34,15,16}
对第4次操作,和为1+10+24=35,模43的结果是35。
对第5次操作,和为29+34+15+16=94,模43的结果是8。
这题建两个lazy数组,一个是加和add,另一个是乘积mul。举个栗子,(ax+b)*c+d=axc+bc+d,可以看出上一层的add(d)对本层的影响就是直接加,上一层的成绩mul(c)对本层的影响还关系到本层的add,所以是本层的mul*=上层的mul,本层的add=上层的add+本层的add(b)*上层的mul(c)。其余就是板子代码了。
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define ll long long const int N=1e5+5; const double eps=1e-8; const double PI = acos(-1.0); #define lowbit(x) (x&(-x)) #define int long long int sum[N<<2],add[N<<2],mul[N<<2]; int a[N],n,m,p; void pushUp(int rt) { sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%p; } void build(int l,int r,int rt) { if(l==r) { sum[rt]=a[l]; return; } int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); pushUp(rt); } void pushDown(int rt,int ln,int rn) //rt根结点 //ln左区间大小,rn为右区间大小 { if(add[rt]||mul[rt]!=1) { mul[rt<<1]=(mul[rt<<1]*mul[rt])%p; mul[rt<<1|1]=(mul[rt<<1|1]*mul[rt])%p; add[rt<<1]=(add[rt]+add[rt<<1]*mul[rt]%p)%p; add[rt<<1|1]=(add[rt]+add[rt<<1|1]*mul[rt]%p)%p; sum[rt<<1]=(sum[rt<<1]*mul[rt]%p+add[rt]*ln%p)%p; sum[rt<<1|1]=(sum[rt<<1|1]*mul[rt]%p+add[rt]*rn%p)%p; add[rt]=0; mul[rt]=1; } } void update(int L,int R,int C,int l,int r,int rt,int o) { if(L <= l && r <= R) { if(o==1) //如果是乘法 { sum[rt]=(sum[rt]*C)%p; mul[rt]=(mul[rt]*C)%p; add[rt]=(add[rt]*C)%p; } else //如果是加法 { sum[rt]=(sum[rt]%p+C%p*(r-l+1)%p)%p; add[rt]=(add[rt]+C)%p; } return ; } int m=(l+r)>>1; pushDown(rt,m-l+1,r-m); if(L <= m) update(L,R,C,l,m,rt<<1,o); if(R > m) update(L,R,C,m+1,r,rt<<1|1,o); pushUp(rt); } int query(int L,int R,int l,int r,int rt) { if(L <= l && r <= R) { return sum[rt]; } int m=(l+r)>>1; pushDown(rt,m-l+1,r-m); int ans=0; if(L <= m) ans+=query(L,R,l,m,rt<<1),ans%=p; if(R > m) ans+=query(L,R,m+1,r,rt<<1|1),ans%=p; ans%=p; return ans; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); while(cin>>n>>p) { memset(add,0,sizeof(add)); fill(mul,mul+(N<<2),1); for(int i=1; i<=n; i++) { cin>>a[i]; } build(1,n,1); cin>>m; while(m--) { ll o,l,r,c; cin>>o>>l>>r; if(o==3) { cout<<query(l,r,1,n,1)<<endl; } else { cin>>c; update(l,r,c,1,n,1,o); } } } return 0; }
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define ll long long ll mod; ll val[100001]; void read(ll &x) { char ch; bool ok; for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1; for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x; } ll m,n,k,a,b; struct Segment_Tree{ #define ls (p<<1) #define rs (p<<1|1) #define mid ((l+r)>>1) ll tree[400050],cnt[400050],res[400050]; void updata(int p) { tree[p]=(tree[ls]+tree[rs])%mod; } void add_lazy(int p,int v,int r) //p为根结点,v为权值,r为区间大小 { tree[p]=(tree[p]+1ll*v*r)%mod; cnt[p]=(cnt[p]+v)%mod; } void res_lazy(int p,int v) { tree[p]=1ll*tree[p]*v%mod; res[p]=1ll*res[p]*v%mod; //res为乘法标记 cnt[p]=1ll*cnt[p]*v%mod; //cnt为加法标记 } void add_pushdown(int p,int l,int r) //加法标记下放 { if(!cnt[p]) return; add_lazy(ls,cnt[p],mid-l+1), //区间为[l,mid] add_lazy(rs,cnt[p],r-mid); //区间为[mid+1,r] cnt[p]=0; } void res_pushdown(int p) //乘法标记下放 { if(res[p]==1) return; res_lazy(rs,res[p]),res_lazy(ls,res[p]); res[p]=1; } void pushdown(int p,int l,int r) { res_pushdown(p); //先放乘法标记 add_pushdown(p,l,r); //再放加法标记 } void build(int p,int l,int r) { cnt[p]=0; res[p]=1; if(l==r) { tree[p]=val[l]; return; } build(ls,l,mid); build(rs,mid+1,r); updata(p); } void change(int p,int l,int r,int a,int b,int v,int v1) { if(l>=a&&r<=b) { res_lazy(p,v1); add_lazy(p,v,r-l+1); return; } pushdown(p,l,r); if(a<=mid) change(ls,l,mid,a,b,v,v1); if(b>mid) change(rs,mid+1,r,a,b,v,v1); updata(p); } ll query(int p,int l,int r,int a,int b) { if(l>=a&&r<=b) return tree[p]%mod; ll ans=0; pushdown(p,l,r); if(a<=mid) ans=(ans+query(ls,l,mid,a,b))%mod; if(b>mid) ans=(ans+query(rs,mid+1,r,a,b))%mod; return ans%mod; } }tree; int main() { read(n),read(mod); for(int i=1;i<=n;i++) read(val[i]); read(m); tree.build(1,1,n); for(int i=1;i<=m;i++) { ll a,b,c,op;read(op); //op为1时,乘 //op为2时,加 if(op==2) read(a),read(b),read(c), tree.change(1,1,n,a,b,c,1); else if(op==1) read(a),read(b),read(c), tree.change(1,1,n,a,b,0,c); else { read(a),read(b); printf("%lld ",tree.query(1,1,n,a,b)%mod); } } return 0; }