洛谷[P3373]线段树模板2

【模板】线段树 2

题目描述

如题,已知一个数列,你需要进行下面三种操作:

  • 将某区间每一个数乘上 $x$

  • 将某区间每一个数加上 $x$

  • 求出某区间每一个数的和

输入格式

第一行包含三个整数 $n,m,p$,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含 $n$ 个用空格分隔的整数,其中第 $i$ 个数字表示数列第 $i$ 项的初始值。

接下来 $m$ 行每行包含若干个整数,表示一个操作,具体如下:

操作 $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

样例输入 #1

1
2
3
4
5
6
7
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

1
2
17
2

提示

【数据范围】

对于 $30%$ 的数据:$n \le 8$,$m \le 10$
对于 $70%$ 的数据:$n \le 10^3 $,$ m \le 10^4$
对于 $100%$ 的数据:$ n \le 10^5$,$ m \le 10^5$

除样例外,$p = 571373$

(数据已经过加强^_^)

样例说明:

故输出应为 $17$、$2$( $40 \bmod 38 = 2$ )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <cstdio>
#include <algorithm>
using namespace std;

#define lr rt << 1
#define rr rt << 1 | 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
typedef long long LL;
const int maxn = 500007;

namespace _lgl{

int N, M, P, a, b, c;
LL sum[maxn << 2], add[maxn << 2], mul[maxn << 2];

inline void up(int rt){
sum[rt] = sum[lr] + sum[rr];
}

inline void down(int rt, int m){
if(mul[rt] != 1){
LL s = mul[rt];
// add[rt] = (add[rt] * s) % P;
mul[lr] = (mul[lr] * s) % P;
mul[rr] = (mul[rr] * s) % P;
add[lr] = (add[lr] * s) % P;
add[rr] = (add[rr] * s) % P;
sum[lr] = (sum[lr] * s) % P;
sum[rr] = (sum[rr] * s) % P;
mul[rt] = 1;
}
if(add[rt]){
LL s = add[rt];
add[lr] = (add[lr] + s) % P;
add[rr] = (add[rr] + s) % P;
sum[lr] = (sum[lr] + (add[rt] * (m - (m >> 1)))) % P;
sum[rr] = (sum[rr] + (add[rt] * (m >> 1))) % P;
add[rt] = 0;
}

}

/*inline void down(int rt, int m){
if(mul[rt] != 1){
add[rt] = add[rt] * mul[rt] % P;
sum[lr] = sum[lr] * mul[rt] % P;
sum[rr] *= mul[rt]%P;
add[lr] *= mul[rt]%P;
add[rr] *= mul[rt]%P;
mul[lr] *= mul[rt]%P;
mul[rr] *= mul[rt]%P;
mul[rt] = 1;
}
if(add[rt]){
add[lr] += add[rt]%P;
add[rr] += add[rt]%P;
sum[lr] += add[rt] * (m - (m >> 1)) % P;
sum[rr] += add[rt] * (m >> 1) % P;
add[rt] = 0;
}
}*/

inline void build(int l, int r, int rt){
mul[rt] = 1;
if(l == r){
scanf("%lld",&sum[rt]);
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
up(rt);
}

inline void update_1(int L, int R, int c, int l, int r, int rt){
if(L <= l && r <= R) {
add[rt] = (add[rt] + c) % P;
sum[rt] = (sum[rt] + (LL) c * (r - l + 1))%P;
return;
}
down(rt, r - l + 1);
int m = (l + r) >> 1;
if(L <= m) update_1(L, R, c, lson);
if(m < R) update_1(L, R, c, rson);
up(rt);
}

inline void update_2(int L, int R, int c, int l, int r, int rt){
if(L <= l && r <= R){
mul[rt] = (mul[rt] * c) % P;
add[rt] = (add[rt] * c) % P;
sum[rt] = (sum[rt] * c) % P;
return;
}
down(rt, r - l + 1);
int m = (l + r) >> 1;
if(L <= m) update_2(L, R, c, lson);
if(m < R) update_2(L, R, c, rson);
up(rt);
}

inline LL query(int L, int R, int l, int r, int rt){
if(L <= l && r <= R) return sum[rt];
down(rt, r - l + 1);
LL ret = 0;
int m = (l + r) >> 1;
if(L <= m) ret = ret + (query(L, R, lson))%P;
if(m < R) ret = ret + (query(L, R, rson))%P;
return ret%P;
}

inline void main(){
freopen("testdata.in.txt","r",stdin);
scanf("%d%d%d",&N,&M,&P);
build(1, N, 1);
while(M--){
scanf("%d",&a);
if(a == 2){
scanf("%d%d%d",&a,&b,&c);
update_1(a, b, c, 1, N, 1);
}else if(a == 1){
scanf("%d%d%d",&a,&b,&c);
update_2(a, b, c, 1, N, 1);
}else{
scanf("%d%d",&a,&b);
printf("%lld\n",query(a, b, 1, N, 1)%P);
}
}
}

}

int main(){
_lgl::main();
return 0;
}