Description
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。
Solution
第一次接触这种多个tag的线段树
学习新东西的时候总是痛苦的,比如wa三个小时都读不进longlong调不出来结果是改用读入优化就对了之类的
咳咳,对于加号乘号的优先级问题我们这样处理。
(a+b)∗c
的改写成
a∗c+b∗c
a∗b+c
的不影响所以不用管
那么在下传的时候修改的时候注意一下就好了。
Code
#include <stdio.h>
#define rep(i, st, ed) for (ll i = st; i <= ed; i += 1)
#define ll long long
#define N 100001
ll mod;
struct seg{int l, r; ll sum, add, mul;}t[N * 5 + 1];
inline ll read(){
ll x = 0;
char ch = getchar();
while (ch < '0' || ch > '9'){
ch = getchar();
}
while (ch >= '0' && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return x;
}
inline void pushDown(int now, ll len){
if (len == 1){
return;
}
ll mul = t[now].mul, add = t[now].add;
int l = now * 2, r = now * 2 + 1;
t[l].sum = ((t[l].sum * mul)%mod + ((len - len / 2) * add)%mod)%mod;
t[r].sum = ((t[r].sum * mul)%mod + ((len / 2) * add)%mod)%mod;
t[l].add = ((mul * t[l].add)%mod + add)%mod;
t[r].add = ((mul * t[r].add)%mod + add)%mod;
t[l].mul = (t[l].mul * mul)%mod;
t[r].mul = (t[r].mul * mul)%mod;
t[now].add = 0;
t[now].mul = 1;
}
inline ll query(int now, int l, int r){
int mid = (t[now].l + t[now].r) >> 1;
if (t[now].l == l && t[now].r == r){
return t[now].sum;
}
pushDown(now, t[now].r - t[now].l + 1);
ll ret;
if (r <= mid){
ret = query(now * 2, l, r)%mod;
}else if (l > mid){
ret = query(now * 2 + 1, l, r)%mod;
}else{
ret = (query(now * 2, l, mid) + query(now * 2 + 1, mid + 1, r))%mod;
}
// t[now].sum = (t[now * 2].sum + t[now * 2 + 1].sum)%mod;
return ret;
}
inline void modify(int now, int l, int r, ll add, ll mul){
ll mid = (t[now].l + t[now].r) >> 1;
if (t[now].l == l && t[now].r == r){
t[now].sum = ((t[now].sum * mul)%mod + ((t[now].r - t[now].l + 1) * add)%mod)%mod;
t[now].mul = (t[now].mul * mul)%mod;
t[now].add = ((t[now].add * mul)%mod + add)%mod;
return;
}
pushDown(now, t[now].r - t[now].l + 1);
if (r <= mid){
modify(now * 2, l, r, add, mul);
}else if (l > mid){
modify(now * 2 + 1, l, r, add, mul);
}else{
modify(now * 2, l, mid, add, mul);
modify(now * 2 + 1, mid + 1, r, add, mul);
}
t[now].sum = (t[now * 2].sum + t[now * 2 + 1].sum)%mod;
}
inline void build(int now, int l, int r){
int mid = (l + r) >> 1;
t[now] = (seg){l, r, 0, 0, 1};
if (l == r){
t[now].sum = read();
return;
}
build(now * 2, l, mid);
build(now * 2 + 1, mid + 1, r);
t[now].sum = (t[now * 2].sum + t[now * 2 + 1].sum)%mod;
}
int main(void){
// freopen("data.in","r",stdin);
// freopen("myp.out","w",stdout);
int n = read();
mod = read();
build(1, 1, n);
int T = read();
while (T --){
int opt = read(), x = read(), y = read();
if (opt == 1){
ll mul = read(), add = 0;
mul = mul % mod;
modify(1, x, y, add, mul);
}else if (opt == 2){
ll add = read(), mul = 1;
add = add % mod;
modify(1, x, y, add, mul);
}else if (opt == 3){
ll prt = query(1, x, y);
printf("%lld\n", prt);
}
}
return 0;
}