1 #include<bits/stdc++.h>
2 #define LL long long
3 #define L(x) x<<1 //左儿子 x*2
4 #define R(x) x<<1|1 //右儿子 x*2+1
5 const int maxn =1e5+5;
6 using namespace std;
7 LL n,m,num[maxn];
8 LL mod; //膜数
9 inline LL read() {
10 LL x=0,f=1;
11 char ch=getchar();
12 while(ch<'0'||ch>'9') f=(ch=='-')?-1:1,ch=getchar();
13 while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
14 return x*f;
15 }
16 struct T {
17 LL l,r;
18 LL sum,add,mul;
19 } tree[maxn<<2];//注意开long long 和四倍空间
20 inline void update(LL p) {
21 tree[p].sum=(tree[L(p)].sum+tree[R(p)].sum)%mod;
22 return;
23 }
24 inline void spread(LL p) {
25 LL mid=(tree[p].l+tree[p].r)>>1;
26 if(tree[p].mul!=1) {
27 tree[L(p)].mul=(tree[L(p)].mul*tree[p].mul)%mod;
28 tree[R(p)].mul=(tree[R(p)].mul*tree[p].mul)%mod;
29 tree[L(p)].add=(tree[L(p)].add*tree[p].mul)%mod;
30 tree[R(p)].add=(tree[R(p)].add*tree[p].mul)%mod;
31 tree[L(p)].sum=(tree[L(p)].sum*tree[p].mul)%mod;
32 tree[R(p)].sum=(tree[R(p)].sum*tree[p].mul)%mod;
33 tree[p].mul=1;
34 }
35 if(tree[p].add) {
36 tree[L(p)].add=(tree[L(p)].add+tree[p].add)%mod;
37 tree[R(p)].add=(tree[R(p)].add+tree[p].add)%mod;
38 tree[L(p)].sum=(tree[L(p)].sum+tree[p].add*(mid-tree[p].l+1))%mod;
39 tree[R(p)].sum=(tree[R(p)].sum+tree[p].add*(tree[p].r-mid))%mod;//tree[p].r-mid不加1
40 tree[p].add=0;
41 }
42 return;
43 }
44 inline void build(LL l,LL r,LL p) {//建树
45 tree[p].l=l,tree[p].r=r,tree[p].mul=1;
46 if(l==r) {
47 tree[p].sum=num[l];
48 tree[p].mul=1;
49 return;
50 }
51 LL mid=(tree[p].l+tree[p].r)>>1;
52 build(l,mid,L(p));
53 build(mid+1,r,R(p));
54 update(p);
55 return;
56 }
57 inline void change1(LL l,LL r,LL p,LL v) {//区间增值
58 if(tree[p].l==l&&tree[p].r==r) {
59 tree[p].add=(tree[p].add+v)%mod;
60 tree[p].sum=(tree[p].sum+v*(r-l+1))%mod;
61 return;
62 }
63 spread(p);
64 LL mid=(tree[p].l+tree[p].r)>>1;
65 if(r<=mid) change1(l,r,L(p),v);
66 else if(l>mid) change1(l,r,R(p),v);
67 else change1(l,mid,L(p),v),change1(mid+1,r,R(p),v);
68 update(p);
69 return;
70 }
71 inline void change2(LL l,LL r,LL p,LL v) {//区间乘法
72
73 if(tree[p].l==l&&tree[p].r==r) {
74 tree[p].mul=(tree[p].mul*v)%mod;
75 tree[p].sum=(tree[p].sum*v)%mod;
76 tree[p].add=(tree[p].add*v)%mod;
77 return;
78 }
79 spread(p);
80 LL mid=(tree[p].l+tree[p].r)>>1;
81 if(r<=mid) change2(l,r,L(p),v);
82 else if(l>mid) change2(l,r,R(p),v);
83 else change2(l,mid,L(p),v),change2(mid+1,r,R(p),v);
84 update(p);
85 return;
86 }
87 inline LL ask_sum1(LL l,LL r,LL p) {//区间和
88 if(tree[p].l==l&&tree[p].r==r) {
89 return tree[p].sum%mod;
90 }
91 spread(p);
92 LL mid=(tree[p].l+tree[p].r)>>1;
93 if(r<=mid) return ask_sum1(l,r,L(p))%mod;
94 else if(l>mid) return ask_sum1(l,r,R(p))%mod;
95 else return (ask_sum1(l,mid,L(p))%mod+ask_sum1(mid+1,r,R(p))%mod)%mod;
96 }
97
98 inline LL ask_sum2(LL l,LL r,LL p) {//区间平方和
99 if(tree[p].l==tree[p].r) {
100 return tree[p].sum*tree[p].sum;
101 }
102 spread(p);
103 LL mid=(tree[p].l+tree[p].r)>>1;
104 if(r<=mid) return ask_sum2(l,r,L(p));
105 else if(l>mid) return ask_sum2(l,r,R(p));
106 else return ask_sum2(l,mid,L(p))+ask_sum2(mid+1,r,R(p));
107 }
108
109 LL opt,l,r,v;
110 int main() {
111 n=read(),m=read();
112 mod=read();
113 for(int i=1; i<=n; i++) num[i]=read();
114 build(1,n,1);
115 while(m--) {
116 opt=read();
117 if(opt==3) {
118 l=read(),r=read();
119 printf("%lld\n",ask_sum1(l,r,1)%mod);//询问区间和
120 }
121 if(opt==4) {
122 l=read(),r=read();
123 printf("%lld\n",ask_sum2(l,r,1)%mod);//询问区间平方和
124 }
125 if(opt==1) {
126 l=read(),r=read(),v=read();
127 change2(l,r,1,v);//区间乘
128 }
129 if(opt==2) {
130 l=read(),r=read(),v=read();
131 change1(l,r,1,v);//区间加
132 }
133 }
134 return 0;
135 }