时/空限制: 1s / 64MB
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。
有长为 NN 的数列,不妨设为 a1,a2,…,aNa1,a2,…,aN 。
有如下三种操作形式:
- 把数列中的一段数全部乘一个值;
- 把数列中的一段数全部加一个值;
- 询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 PP 的值。
输入格式
第一行两个整数 NN 和 PP ;
第二行含有 NN 个非负整数,从左到右依次为 a1,a2,…,aNa1,a2,…,aN ;
第三行有一个整数 MM ,表示操作总数;
从第四行开始每行描述一个操作,输入的操作有以下三种形式:
- 操作 11 :
1 t g c
,表示把所有满足 t≤i≤gt≤i≤g 的 aiai 改为 ai×cai×c ; - 操作 22 :
2 t g c
,表示把所有满足 t≤i≤gt≤i≤g 的 aiai 改为 ai+cai+c ; - 操作 33 :
3 t g
,询问所有满足 t≤i≤gt≤i≤g 的 aiai 的和模 PP 的值。
同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
输出格式
对每个操作 33 ,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
数据范围
1≤N,M≤1051≤N,M≤105 ,
1≤t≤g≤N1≤t≤g≤N ,
0≤c,ai≤1090≤c,ai≤109 ,
1≤P≤1091≤P≤109
输入样例:
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
输出样例:
2
35
8
样例解释
初始时数列为 {1,2,3,4,5,6,7}{1,2,3,4,5,6,7} ;
经过第 11 次操作后,数列为 {1,10,15,20,25,6,7}{1,10,15,20,25,6,7} ;
对第 22 次操作,和为 10+15+20=4510+15+20=45 ,模 4343 的结果是 22 ;
经过第 33 次操作后,数列为 {1,10,24,29,34,15,16}{1,10,24,29,34,15,16} ;
对第 44 次操作,和为 1+10+24=351+10+24=35 ,模 4343 的结果是 3535 ;
对第 55 次操作,和为 29+34+15+16=9429+34+15+16=94 ,模 4343 的结果是 88 。
思路:
利用懒标计维护两个值:累加值和累乘值,关键点在于如何更新这两个值,看代码。
#include<iostream>
#define ll long long
using namespace std;
const int N = 100000 + 10;
struct node{
int l, r;
ll sum, add, mul;
}tr[N*4];
ll a[N];
int n,p,m;
void pushup(node &u, node &l, node &r)
{
u.sum = (l.sum + r.sum) % p;
}
void pushup(int u)
{
pushup(tr[u], tr[u<<1], tr[u<<1|1]);
}
void eval(node &u, ll add, ll mul)
{
u.sum = (u.sum * mul + (u.r - u.l + 1) * add) % p;
u.mul = (mul * u.mul) % p;
u.add = (u.add * mul + add) % p;
}
void pushdown(int u)//使用懒标计更新子节点
{
eval(tr[u<<1], tr[u].add, tr[u].mul);
eval(tr[u<<1|1], tr[u].add, tr[u].mul);
tr[u].add = 0;
tr[u].mul = 1;
}
void build(int u, int l, int r)
{
if(l == r) tr[u] = {l, r, a[l], 0, 1};
else
{
tr[u] = {l,r,0,0,1};
int mid = (l + r) >> 1;
build(u<<1, l, mid);
build(u<<1|1, mid+1, r);
pushup(u);
}
}
ll query(int u, int l, int r)
{
if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
ll sum = 0;
if(l <= mid) sum += query(u<<1, l, r);
if(r > mid) sum = (sum + query(u<<1|1, l, r)) % p;
return sum;
}
void modify(int u, int l, int r, ll add, ll mul)
{
if(tr[u].l >= l && tr[u].r <= r)
{
eval(tr[u], add, mul);
}
else
{
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid) modify(u<<1, l, r, add, mul);
if(r > mid) modify(u<<1|1, l, r, add, mul);
pushup(u);
}
}
int main()
{
cin>>n>>p;
for(int i=1; i<=n; i++)
scanf("%lld",&a[i]);
build(1, 1, n);
int c;
cin>>m;
while(m--)
{
cin>>c;
if(c == 1)
{
int l,r;
ll v;
cin>>l>>r>>v;
modify(1, l, r, 0, v);
}
else if(c == 2)
{
int l,r;
ll v;
cin>>l>>r>>v;
modify(1, l, r, v, 1);
}
else
{
int l, r;
cin>>l>>r;
cout<<query(1, l, r)<<endl;
}
}
return 0;
}