题目描述
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式:
(1)把数列中的一段数全部乘一个值;
(2)把数列中的一段数全部加一个值;
(3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。
输入输出格式
输入格式:
第一行两个整数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)。
同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
输出格式:
对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
不得不说,这题让我对lazy的理解加深了一步
需要考虑乘与加的优先性
我们设sum是区间和,len为区间长,(x)代表乘上或加上的值
tag1为lazy_add,tag2为lazy_mul
如果我们先加再乘,即:(sum+tag1(ast)len)(ast)tag2**
则乘法操作: (sum+tag1(ast)len)(ast)tag2(ast)x是不会有影响的,所以tar1不变,tar2相乘
但加法操作 (sum+tag1(ast)len)(ast)tag2+x(ast)len
转化后 (sum+len(x(ackslash)tag2+tag1))(ast)tag2。所以这里的tar1+=x(ackslash)tag2,tar1不变
但这样tar1会出现精度问题
所以考虑先乘后加
sum(ast)tag2 (+)tag1(ast)len
则乘法操作: (sum(ast)tag2 +tag1(*)len)(ast x)
很容易看出我们应该
将 tag1(ast)=(x),tag2(ast)=(x)
则加法操作: (sum(ast)tag2 (+)tag1*len)+x(*)len
则只需要将 tar1+=(x),tar2 不变
代码
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int maxn=200000+10;
struct tag
{
long long add,mul;
}lazy[maxn<<2];
int n,m;
long long p;
long long sum[maxn<<2];
long long res=0;
inline long long read()
{
long long x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
inline void pushup(int rt)
{
sum[rt]=sum[lson]+sum[rson];
sum[rt]%=p;
return;
}
inline void pushdown(int rt,int m)
{
sum[lson]=sum[lson]*lazy[rt].mul+lazy[rt].add*(m-(m>>1));
sum[lson]%=p;
sum[rson]=sum[rson]*lazy[rt].mul+lazy[rt].add*(m>>1);
sum[rson]%=p;
lazy[lson].add=lazy[lson].add*lazy[rt].mul+lazy[rt].add;
lazy[lson].add%=p;
lazy[rson].add=lazy[rson].add*lazy[rt].mul+lazy[rt].add;
lazy[rson].add%=p;
lazy[lson].mul*=lazy[rt].mul;
lazy[lson].mul%=p;
lazy[rson].mul*=lazy[rt].mul;
lazy[rson].mul%=p;
lazy[rt].mul=1;
lazy[rt].add=0;
return;
}
inline void build(int l,int r,int rt)
{
lazy[rt].add=0;
lazy[rt].mul=1;
if(l==r)
{
sum[rt]=read();
sum[rt]%=p;
return;
}
int m=(l+r)>>1;
build(l,m,lson);
build(m+1,r,rson);
pushup(rt);
}
inline void update_add(int L,int R,int c,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
lazy[rt].add+=c;
lazy[rt].add%=p;
sum[rt]+=c*(r-l+1);
sum[rt]%=p;
return;
}
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m)
update_add(L,R,c,l,m,lson);
if(m<R)
update_add(L,R,c,m+1,r,rson);
pushup(rt);
}
inline void update_mul(int L,int R,int c,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
lazy[rt].mul*=c;
lazy[rt].mul%=p;
lazy[rt].add*=c;
lazy[rt].add%=p;
sum[rt]*=c;
sum[rt]%=p;
return;
}
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m)
update_mul(L,R,c,l,m,lson);
if(m<R)
update_mul(L,R,c,m+1,r,rson);
pushup(rt);
}
void query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
res+=sum[rt];
res%=p;
return;
}
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m)
query(L,R,l,m,lson);
if(m<R)
query(L,R,m+1,r,rson);
}
int main()
{
n=read(),p=read();
build(1,n,1);
m=read();
for(int i=1;i<=m;i++)
{
int op=read();
if(op==1)
{
int x=read(),y=read(),k=read();
update_mul(x,y,k,1,n,1);
}
if(op==2)
{
int x=read(),y=read(),k=read();
update_add(x,y,k,1,n,1);
}
if(op==3)
{
int x=read(),y=read();res=0;
query(x,y,1,n,1);
printf("%lld
",res);
}
}
return 0;
}