板子集合
目录:
1.DIJ && SPFA
2.LCA
3.缩点
4.字符串哈希
5.最小生成树
6.xxs
7.并查集
8.ST表
9.单调队列
10.单调栈
11.乘法逆元1(线性求逆元)
12.乘法逆元2(费马小,快速幂)
13.tarjan求割点(割顶)
14.树链剖分
15.二分图最大匹配
16.矩阵快速幂
17.线段树
//1.DIJ && SPFA
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100000+10,maxm=500000+10;
struct node{
int to,nxt,val;
}edge[maxm<<1];
int head[maxn];
ll min_dis[maxn];
bool vis[maxn];
int n,m,cnt,s;
void add(int from,int to,int val){
edge[++cnt].to=to;
edge[cnt].val=val;
edge[cnt].nxt=head[from];
head[from]=cnt;
}
void SPFA(){
memset(min_dis,0x3f,sizeof(min_dis));
memset(vis,0,sizeof(vis));
min_dis[s]=0;
queue <int> q;
q.push(s);
vis[s]=1;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(min_dis[v]>min_dis[u]+edge[i].val){
min_dis[v]=min_dis[u]+edge[i].val;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
}
struct Node{
int data;
ll dis;
Node(){}
Node(int x,ll y){
data=x;
dis=y;
}
bool operator < (const Node &A) const{
return dis>A.dis ;
}
};
priority_queue <Node> q;
void Dij(){
memset(min_dis,0x3f,sizeof(min_dis));
memset(vis,0,sizeof(vis));
q.push(Node(s,0));
min_dis[s]=0;
while(!q.empty()){
Node t=q.top();
q.pop();
int u=t.data;
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(min_dis[v]>min_dis[u]+edge[i].val){
min_dis[v]=min_dis[u]+edge[i].val;
q.push(Node(v,min_dis[v]));
}
}
}
}
void Solve(){
scanf("%d%d%d",&n,&m,&s);
for(int i=1,x,y,z;i<=m;++i){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
Dij();//SPFA();
for(int i=1;i<=n;++i){
if(min_dis[i]==0x3f3f3f3f3f3f3f3f) printf("%d ",2147483647);
else printf("%lld ",min_dis[i]);
}
}
int main(){
Solve();
return 0;
}
//2.LCA
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=500000+10;
struct node{
int to,nxt;
}edge[maxn<<1];
int n,m,cnt,s;
int depth[maxn],size[maxn],fa[maxn],son[maxn],top[maxn],head[maxn];
void add(int from,int to){
edge[++cnt].to=to;
edge[cnt].nxt=head[from];
head[from]=cnt;
}
void dfs1(int u,int f){
size[u]=1;
fa[u]=f;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==f) continue;
depth[v]=depth[u]+1;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t;
if(son[u]) dfs2(son[u],t);
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
int Lca(int u,int v){
while(top[u]!=top[v]){
if(depth[top[u]]<depth[top[v]]) swap(v,u);
u=fa[top[u]];
}
return depth[u]>depth[v] ? v : u ;
}
void Solve(){
scanf("%d%d%d",&n,&m,&s);
for(int i=2,x,y;i<=n;++i){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs1(s,0);
dfs2(s,s);
for(int i=1,x,y;i<=m;++i){
scanf("%d%d",&x,&y);
printf("%d\n",Lca(x,y));
}
}
int main(){
Solve();
return 0;
}
//3.缩点
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100000+10;
struct node{
int to,nxt;
}edge[maxn],e[maxn];
int f[maxn],belong[maxn],ind[maxn],size[maxn],a[maxn],head[maxn],head2[maxn],vis[maxn],dfn[maxn],low[maxn],Stack[maxn];
int cnt,n,m,tot,Time,top,cnt2;
void add(int from,int to){
edge[++cnt].to=to;
edge[cnt].nxt=head[from];
head[from]=cnt;
}
void add2(int from,int to){
e[++cnt2].to=to;
e[cnt2].nxt=head2[from];
head2[from]=cnt2;
}
void tarjan(int u){
if(dfn[u]) return;
dfn[u]=low[u]=++Time;
Stack[++top]=u;
vis[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(vis[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
++tot;
while(Stack[top+1]!=u){
int t=Stack[top];
top--;
vis[t]=0;
belong[t]=tot;
size[tot]+=a[t];
}
}
}
void Solve(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1,x,y;i<=m;++i){
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;++i) tarjan(i);
for(int u=1;u<=n;++u){
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(belong[u]!=belong[v]){
add2(belong[u],belong[v]);
ind[belong[v]]++;
}
}
}
queue <int> q;
for(int i=1;i<=tot;++i){
if(ind[i]==0){
q.push(i);
f[i]=size[i];
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head2[u];i;i=e[i].nxt){
int v=e[i].to;
f[v]=max(f[v],size[v]+f[u]);
ind[v]--;
if(ind[v]==0) q.push(v);
}
}
int ans=0;
for(int i=1;i<=tot;++i) ans=max(ans,f[i]);
printf("%d\n",ans);
}
int main(){
Solve();
return 0;
}
//4.字符串哈希
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long llu;
const int maxn=100000+10;
const llu base=233;
int n;
char s[maxn];
llu ha[maxn];
bool cmp(llu x,llu y){
return x<y;
}
void Solve(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%s",s+1);
int len=strlen(s+1);
for(int j=1;j<=len;++j) ha[i]=ha[i]*base+s[j]-'A'+1;
}
sort(ha+1,ha+n+1,cmp);
int ans=unique(ha+1,ha+n+1)-ha-1;
printf("%d\n",ans);
}
int main(){
Solve();
return 0;
}
//5.最小生成树
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=200000+10;
struct node{
int from,to,val;
}edge[maxn];
int n,m;
ll ans;
int fa[maxn];
bool cmp(node x,node y){
return x.val<y.val;
}
int find(int x){
return fa[x]==x ? x : (fa[x]=find(fa[x])) ;
}
void Solve(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) fa[i]=i;
for(int i=1;i<=m;++i){
scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].val);
}
sort(edge+1,edge+m+1,cmp);
for(int i=1;i<=m;++i){
int x=edge[i].from;
int y=edge[i].to;
int rx=find(x);
int ry=find(y);
if(rx==ry) continue;
fa[rx]=ry;
int d=edge[i].val;
ans+=d;
}
for(int i=2;i<=n;++i){
if(find(i)!=find(i-1)){
printf("orz\n");
return;
}
}
printf("%lld\n",ans);
}
int main(){
Solve();
return 0;
}
//6.xxs
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100000000+10;
int prime[maxn];
bool is_not_prime[maxn];
int cnt;
int n,q;
void xxs(){
is_not_prime[0]=is_not_prime[0]=1;
for(int i=2;i<=n;++i){
if(!is_not_prime[i]){
prime[++cnt]=i;
}
for(int j=1;j<=cnt&&prime[j]*i<=n;++j){
is_not_prime[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
void Solve(){
scanf("%d%d",&n,&q);
xxs();
for(int i=1,x;i<=q;++i){
scanf("%d",&x);
printf("%d\n",prime[x]);
}
}
int main(){
Solve();
return 0;
}
//7.并查集
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100000+10;
int fa[maxn];
int n,m;
int find(int x){
return fa[x]==x ? x : (fa[x]=find(fa[x])) ;
}
void Merge(int x,int y){
int rx=find(x);
int ry=find(y);
if(rx==ry) return;
fa[rx]=ry;
}
void Solve(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) fa[i]=i;
for(int i=1,op,x,y;i<=m;++i){
scanf("%d%d%d",&op,&x,&y);
if(op==1) Merge(x,y);
else if(find(x)==find(y)) printf("Y\n");
else printf("N\n");
}
}
int main(){
Solve();
return 0;
}
//8.ST表
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100000+10;
int n,m;
int pmax[maxn][30];
int read(){
int w=0,x=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') x=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
w=(w<<1)+(w<<3)+(ch^48);
ch=getchar();
}
return w*x;
}
int log_2(int x){
int cnt=-1;
while(x){
x>>=1;
cnt++;
}
return cnt;
}
int qmax(int l,int r){
int k=log_2(r-l+1);
return max(pmax[l][k],pmax[r-(1<<k)+1][k]);
}
void Solve(){
n=read();m=read();
for(int i=1;i<=n;++i) pmax[i][0]=read();
for(int j=1;j<=16;++j){
for(int i=1;i+(1<<j)-1<=n;++i){
pmax[i][j]=max(pmax[i][j-1],pmax[i+(1<<(j-1))][j-1]);
}
}
for(int i=1,x,y;i<=m;++i){
x=read();
y=read();
printf("%d\n",qmax(x,y));
}
}
int main(){
Solve();
return 0;
}
//9.单调队列
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
deque <int> q1;//q1维护区间最大值;
deque <int> q2;//q2维护区间最小值;
int cnt_min[maxn],cnt_max[maxn];
//cnt数组分别维护以i为结尾的最大,最小值的编号;
ll a[maxn];
int n,len;
void Solve(){
scanf("%d%d",&n,&len);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
for(int i=1;i<=n;++i){
while(!q1.empty()&&a[i]>=a[q1.back()]) q1.pop_back();
q1.push_back(i);
while(!q1.empty()&&i-len+1>q1.front()) q1.pop_front();
if(i-len+1>0) cnt_max[i]=q1.front();
}
for(int i=1;i<=n;++i){
while(!q2.empty()&&a[i]<=a[q2.back()]) q2.pop_back();
q2.push_back(i);
while(!q2.empty()&&i-len+1>q2.front()) q2.pop_front();
if(i-len+1>0) cnt_min[i]=q2.front();
}
for(int i=len;i<=n;++i) printf("%lld ",a[cnt_min[i]]);
printf("\n");
for(int i=len;i<=n;++i) printf("%lld ",a[cnt_max[i]]);
}
int main(){
Solve();
return 0;
}
//10.单调栈
#include <bits/stdc++.h>
using namespace std;
const int maxn=3e6+10;
int Stack[maxn],a[maxn],f[maxn];
int top,n;
void Solve(){
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
Stack[++top]=1;
for(int i=2;i<=n;++i){
while(top>0&&a[i]>a[Stack[top]]){
int t=Stack[top];
top--;
f[t]=i;
}
Stack[++top]=i;
}
for(int i=1;i<=n;++i) printf("%d ",f[i]);
}
int main(){
Solve();
return 0;
}
//11.乘法逆元1(线性求逆元)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e6+10;
ll ny[maxn];
int p,n;
void Solve(){
scanf("%d%d",&n,&p);
ny[1]=1;
printf("1\n");
for(int i=2;i<=n;++i){
ny[i]=(ll)(p-p/i)*ny[p%i]%p;
printf("%lld\n",ny[i]);
}
}
int main(){
Solve();
return 0;
}
//12.乘法逆元2(费马小,快速幂)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e6+10;
ll a[maxn],sum[maxn],sum2[maxn];
ll ans,l,r;
int p,n,k;
inline ll read(){
ll x=0,f=1;
char ch=getchar();
while (!isdigit(ch)){
if (ch=='-') f=-1;
ch=getchar();
}
while (isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
ll qpow(ll a,ll b){
ll base=a,res=1;
while(b){
if(b&1) res=res*base%p;
base=base*base%p;
b>>=1;
}
return res%p;
}
void Solve(){
scanf("%d%d%d",&n,&p,&k);
sum[0]=sum2[n+1]=1ll;
for(register int i=1;i<=n;++i){
a[i]=read();
sum[i]=a[i]*sum[i-1]%p;
}
for(register int i=n;i>0;--i) sum2[i]=a[i]*sum2[i+1]%p;
ll base1=1ll;
for(register int i=1;i<=n;++i){
base1=base1*k%p;
ans=(ans+base1*sum[i-1]%p*sum2[i+1])%p;
}
ans=ans*qpow(sum[n],p-2)%p;
printf("%lld\n",ans);
}
int main(){
Solve();
return 0;
}
//13.tarjan求割点(割顶)
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e4+10,maxm=2e5+10;
int is_cut[maxn],head[maxn],low[maxn],dfn[maxn];
struct node{
int to,next;
}edge[maxm];
int cnt,Time,n,m,tot;
void add(int from,int to){
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
void tarjan(int u,int f){
int num=0;
low[u]=dfn[u]=++Time;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(!dfn[v]){
tarjan(v,u);
low[u]=min(low[u],low[v]);
if((!f&&++num>1)||(f&&low[v]>=dfn[u])) is_cut[u]=1;
}else if(v!=f) low[u]=min(low[u],dfn[v]);
}
}
void Solve(){
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<=m;++i){
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i,0);
for(int i=1;i<=n;++i) if(is_cut[i]) tot++;
printf("%d\n",tot);
for(int i=1;i<=n;++i) if(is_cut[i]) printf("%d ",i);
}
int main(){
Solve();
return 0;
}
//14.树链剖分
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100000+10;
ll tree[maxn<<2],lazy[maxn<<2];
int a[maxn],head[maxn],w[maxn],size[maxn],top[maxn],depth[maxn],fa[maxn],son[maxn],dfn[maxn];
int n,m,rt,p,cnt,Time;
struct node{
int to,next;
}edge[maxn<<1];
void add(int from,int to){
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
void dfs1(int u,int f){
size[u]=1;
fa[u]=f;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v==f) continue;
depth[v]=depth[u]+1;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t){
dfn[u]=++Time;
top[u]=t;
w[Time]=a[u];
if(son[u]) dfs2(son[u],t);
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
void build(int rt,int l,int r){
if(l==r){
tree[rt]=w[l]%p;
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
tree[rt]=(tree[rt<<1]+tree[rt<<1|1])%p;
}
void update(int rt,int l,int r,ll x){
lazy[rt]+=x;
if(lazy[rt]>=p) lazy[rt]-=p;
tree[rt]=(tree[rt]+x*(r-l+1))%p;
}
void pushdown(int rt,int l,int r){
if(lazy[rt]==0) return;
int mid=(l+r)>>1;
update(rt<<1,l,mid,lazy[rt]);
update(rt<<1|1,mid+1,r,lazy[rt]);
lazy[rt]=0;
}
ll query(int rt,int l,int r,int s,int t){
if(s<=l&&r<=t) return tree[rt]%p;
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(t<=mid) return query(rt<<1,l,mid,s,t);
if(s>mid) return query(rt<<1|1,mid+1,r,s,t);
return (query(rt<<1,l,mid,s,t)+query(rt<<1|1,mid+1,r,s,t))%p;
}
ll Query(int u,int v){
ll res=0;
while(top[u]!=top[v]){
if(depth[top[u]]<depth[top[v]]) swap(v,u);
res+=query(1,1,n,dfn[top[u]],dfn[u]);
if(res>=p) res-=p;
u=fa[top[u]];
}
if(depth[u]>depth[v]) swap(v,u);
res+=query(1,1,n,dfn[u],dfn[v]);
if(res>=p) res-=p;
return res;
}
void modify(int rt,int l,int r,int s,int t,int x){
if(s<=l&&r<=t){
update(rt,l,r,(ll)x);
return;
}
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(s<=mid) modify(rt<<1,l,mid,s,t,x);
if(t>mid) modify(rt<<1|1,mid+1,r,s,t,x);
tree[rt]=(tree[rt<<1]+tree[rt<<1|1])%p;
}
void Modify(int u,int v,int x){
while(top[u]!=top[v]){
if(depth[top[u]]<depth[top[v]]) swap(v,u);
modify(1,1,n,dfn[top[u]],dfn[u],x);
u=fa[top[u]];
}
if(depth[u]>depth[v]) swap(u,v);
modify(1,1,n,dfn[u],dfn[v],x);
}
void Solve(){
scanf("%d%d%d%d",&n,&m,&rt,&p);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1,x,y;i<n;++i){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs1(rt,0);
dfs2(rt,rt);
build(1,1,n);
for(int i=1,op,x,y,z;i<=m;++i){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&x,&y,&z);
Modify(x,y,z);
}else if(op==2){
scanf("%d%d",&x,&y);
printf("%lld\n",Query(x,y)%p);
}else if(op==3){
scanf("%d%d",&x,&y);
modify(1,1,n,dfn[x],dfn[x]+size[x]-1,y);
}else{
scanf("%d",&x);
printf("%lld\n",query(1,1,n,dfn[x],dfn[x]+size[x]-1)%p);
}
}
}
int main(){
Solve();
return 0;
}
//15.二分图最大匹配
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6,maxm=1e6+10;
struct node{
int to,next;
}edge[maxm];
int head[maxn],match[maxn],vis[maxn];
int cnt;
int n,m,e,ans,x,y;
void add(int from,int to){
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
bool find(int u){
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(!vis[v]){
vis[v]=1;
if(!match[v]||find(match[v])){
match[v]=u;
return true;
}
}
}
return false;
}
void Solve(){
scanf("%d%d%d",&n,&m,&e);
for(int i=1;i<=e;++i){
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;++i){
memset(vis,0,sizeof(vis));
if(find(i)) ans++;
}
printf("%d",ans);
}
int main(){
Solve();
return 0;
}
//16.矩阵快速幂
#include <bits/stdc++.h>
using namespace std;
const int maxn=100+10,mod=1e9+7;
typedef long long ll;
ll n,k;
struct Matrix{
ll c[maxn][maxn];
}A;
Matrix operator*(const Matrix &x,const Matrix &y){
Matrix a;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
a.c[i][j]=0;
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
for(int k=1;k<=n;++k){
a.c[i][j]=(a.c[i][j]+x.c[i][k]*y.c[k][j]%mod)%mod;
}
}
}
return a;
}
Matrix qpow(){
Matrix s;
for(int i=1;i<=n;++i) s.c[i][i]=1;
while(k){
if(k&1) s=A*s;
A=A*A;
k>>=1;
}
return s;
}
void Solve(){
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
scanf("%lld",&A.c[i][j]);
}
}
Matrix ans=qpow();
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
printf("%lld ",ans.c[i][j]);
}
printf("\n");
}
}
int main(){
Solve();
return 0;
}
//17.线段树
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=100000+10,mod=571343;
struct Segment_tree{
int val,lazyadd,lazyp;
}tree[maxn<<2];
int a[maxn];
int n,m,p;
void build(int rt,int l,int r){
tree[rt].lazyadd=1;
if(l==r){
tree[rt].val=a[l]%p;
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
tree[rt].val=(tree[rt<<1].val+tree[rt<<1|1].val)%p;
}
void updateadd(int rt,int l,int r,int x){
tree[rt].lazyadd=tree[rt].lazyadd*x%p;
tree[rt].lazyp=tree[rt].lazyp*x%p;
tree[rt].val=tree[rt].val*x%p;
}
void updatep(int rt,int l,int r,int x){
tree[rt].lazyp=(tree[rt].lazyp+x)%p;
tree[rt].val=(tree[rt].val+x*(r-l+1))%p;
}
void pushdown(int rt,int l,int r){
int mid=(l+r)>>1;
if(tree[rt].lazyadd!=1){
updateadd(rt<<1,l,mid,tree[rt].lazyadd);
updateadd(rt<<1|1,mid+1,r,tree[rt].lazyadd);
tree[rt].lazyadd=1;
}
if(tree[rt].lazyp){
updatep(rt<<1,l,mid,tree[rt].lazyp);
updatep(rt<<1|1,mid+1,r,tree[rt].lazyp);
tree[rt].lazyp=0;
}
}
void modifyp(int rt,int l,int r,int s,int t,int x){
if(s<=l&&r<=t){
updatep(rt,l,r,x);
return;
}
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(s<=mid) modifyp(rt<<1,l,mid,s,t,x);
if(t>mid) modifyp(rt<<1|1,mid+1,r,s,t,x);
tree[rt].val=(tree[rt<<1].val+tree[rt<<1|1].val)%p;
}
void modifyadd(int rt,int l,int r,int s,int t,int x){
if(s<=l&&r<=t){
updateadd(rt,l,r,x);
return;
}
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(s<=mid) modifyadd(rt<<1,l,mid,s,t,x);
if(t>mid) modifyadd(rt<<1|1,mid+1,r,s,t,x);
tree[rt].val=(tree[rt<<1].val+tree[rt<<1|1].val)%p;
}
int query(int rt,int l,int r,int s,int t){
if(s<=l&&r<=t) return tree[rt].val%p;
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(t<=mid) return query(rt<<1,l,mid,s,t);
if(s>mid) return query(rt<<1|1,mid+1,r,s,t);
return (query(rt<<1,l,mid,s,t)+query(rt<<1|1,mid+1,r,s,t))%p;
}
void Solve(){
scanf("%lld%lld%lld",&n,&m,&p);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
build(1,1,n);
for(int i=1,op,x,y,z;i<=m;++i){
scanf("%lld%lld%lld",&op,&x,&y);
if(op==1){
scanf("%lld",&z);
modifyadd(1,1,n,x,y,z);
}else if(op==2){
scanf("%lld",&z);
modifyp(1,1,n,x,y,z);
}else printf("%lld\n",query(1,1,n,x,y));
}
}
signed main(){
Solve();
return 0;
}