题目描述
如题,已知一个数列,你需要进行下面三种操作:
1.将某区间每一个数乘上x
2.将某区间每一个数加上x
3.求出某区间每一个数的和
输入格式
第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k
操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k
操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果
输出格式
输出包含若干行整数,即为所有操作3的结果。
输入输出样例
输入 #1 复制
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4
输出 #1 复制
17
2
说明/提示
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
(数据已经过加强_)
Ac_code:
#include <bits/stdc++.h>
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
typedef long long LL;
using namespace std;
const LL MAXN = 1e5+5;
LL n,m,mod;
LL sum[MAXN<<2];
LL tag1[MAXN<<2],tag2[MAXN<<2];
LL a[MAXN];
/*
sum: 存区间和
a:存原始数据
tag1: 乘v lazy tag
tag2: 加v lazy tag
*/
inline bool read(LL &x)
{
char ch;
int sign;
if(ch = getchar(),ch==EOF) return 0;
while(ch!='-'&&(!isdigit(ch))) ch = getchar();
sign = (ch=='-')?-1:1;
x = (ch=='-')?0:(ch-'0');
while((ch=getchar())&&isdigit(ch))
x = x*10 + (ch-'0');
x *= sign;
return 1;
}
inline void write(LL x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline void push_up(LL rt)
{
sum[rt] = (sum[rt<<1]+sum[rt<<1|1])%mod;
return;
}
void build(LL rt,LL l,LL r)
{
//lazy tag初始化!!
tag1[rt] = 1;
tag2[rt] = 0;
if(l == r)
{
sum[rt] = a[l];
return;
}
LL mid = (l + r) >> 1;
build(lson);
build(rson);
push_up(rt);
}
inline void push_down(LL rt,LL l,LL r)
{
LL mid = (l + r) >> 1;
//要考虑优先级:不清楚加先还是乘先,而不同顺序结果不同
if(tag1[rt]!=1) //可能乘0!!!
{
tag1[rt<<1] = (tag1[rt<<1] * tag1[rt]) % mod;
sum[rt<<1] = (sum[rt<<1] * tag1[rt]) % mod;
tag1[rt<<1|1] = (tag1[rt<<1|1] * tag1[rt]) % mod;
sum[rt<<1|1] = (sum[rt<<1|1] * tag1[rt]) % mod;
//乘标记下传同时要更新加标记(把即将加的算上)
tag2[rt<<1] = (tag2[rt<<1] * tag1[rt]) % mod;
tag2[rt<<1|1] = (tag2[rt<<1|1] * tag1[rt]) % mod;
tag1[rt] = 1;//mulit init: 1!!
}
if(tag2[rt]>0)
{
tag2[rt<<1] = (tag2[rt<<1] + tag2[rt]) % mod;
sum[rt<<1] = (sum[rt<<1] + (mid-l+1)*tag2[rt]%mod) % mod;
tag2[rt<<1|1] = (tag2[rt<<1|1] + tag2[rt]) % mod;
sum[rt<<1|1] = (sum[rt<<1|1] + (r-mid)*tag2[rt]%mod) % mod;
tag2[rt] = 0;
}
}
//操作区间【L,R】
void update_range(LL L,LL R,LL v,LL op,LL rt,LL l,LL r)
{
if(L <= l && r <= R) //是修改区间子集
{
if(op == 1)
{
/*
现在要对乘lazy tag修改,如果之前有加lazy tag
由于乘优先级高,现在修改乘lazy tag,
会影响加 lazy tag,此时需要同时修改加lazy tag,
把将要加那部分,现在算进来
*/
sum[rt] = (sum[rt] * v) % mod;
tag1[rt] = (tag1[rt] * v) % mod; //tag1累乘
tag2[rt] = (tag2[rt] * v) % mod;//是乘,加也变
}
else
{
/*
现在要对加lazy tag修改,如果之前有乘lazy tag
由于乘优先级高,现在修改加lazy tag,
对最终结果不会有影响
*/
sum[rt] = (sum[rt] + (r-l+1)*v%mod) % mod;
tag2[rt] = (tag2[rt] + v) % mod;//tag2累加
}
return;
}
push_down(rt,l,r); //标记下传
LL mid = (l + r) >> 1;
if(L <= mid)
update_range(L,R,v,op,lson);
if(R > mid)
update_range(L,R,v,op,rson);
push_up(rt); //向上更新信息
}
LL query(LL L,LL R,LL rt,LL l,LL r)
{
if(L <= l && r <= R)//查询区间子集
{
return sum[rt]%mod;
}
push_down(rt,l,r); //标记下传更新可能要涉及到的区间
LL mid = (l + r) >> 1;
LL res = 0;
if(L <= mid) //左孩子涉及
res = (res+query(L,R,lson))%mod;
if(R > mid) //右孩子涉及
res = (res+query(L,R,rson))%mod;
return res%mod;
}
/*
取模过程中,也不能一味的取模,
有些不必要的就可以不取模,否则TLE!!!
*/
int main()
{
//scanf("%lld%lld%lld",&n,&m,&mod);
read(n),read(m),read(mod);
for(LL i = 1; i <= n; i++)
{
//scanf("%lld",&a[i]);
read(a[i]);
}
build(1,1,n);
while(m--)
{
LL op,x,y,k;
//scanf("%lld%lld%lld",&op,&x,&y);
read(op),read(x),read(y);
if(op == 3)
{
//printf("%lld\n",query(x,y,1,1,n));
write(query(x,y,1,1,n));
puts("");
}
else
{
//scanf("%lld",&k);
read(k);
update_range(x,y,k,op,1,1,n);
}
}
return 0;
}