板子集合

目录:
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;
}
posted @ 2022-09-10 10:25  “起个名字真难♘”  阅读(34)  评论(0编辑  收藏  举报