秘制 模板 小全

由于作者代码太丑少部分为原题解

最短路模块

spfa

#include<bits/stdc++.h>
const long long inf=2147483647;
const int maxn=10005;
const int maxm=500005;
using namespace std;
int n,m,s,num_edge=0;
int dis[maxn],vis[maxn],head[maxm];
struct Edge
{
  int next,to,dis;
}edge[maxm]; //结构体表示静态邻接表
void addedge(int from,int to,int dis) //邻接表建图
{ //以下是数据结构书上的标准代码,不懂翻书看解释
  edge[++num_edge].next=head[from]; //链式存储下一条出边
  edge[num_edge].to=to; //当前节点编号
  edge[num_edge].dis=dis; //本条边的距离
  head[from]=num_edge; //记录下一次的出边情况
}
void spfa()
{
  queue<int> q; //spfa用队列,这里用了STL的标准队列
  for(int i=1; i<=n; i++) 
  {
    dis[i]=inf; //带权图初始化
    vis[i]=0; //记录点i是否在队列中,同dijkstra算法中的visited数组
  }
  q.push(s); dis[s]=0; vis[s]=1; //第一个顶点入队,进行标记
  while(!q.empty())
  {
    int u=q.front(); //取出队首
    q.pop(); vis[u]=0; //出队标记
    for(int i=head[u]; i; i=edge[i].next) //邻接表遍历,不多解释了(也可用vector代替)
    {
      int v=edge[i].to; 
      if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改
      {
        dis[v]=dis[u]+edge[i].dis;
        if(vis[v]==0) //未入队则入队
        {
          vis[v]=1; //标记入队
          q.push(v);
        }
      }
    }
  }
}
int main()
{
  cin>>n>>m>>s;
  for(int i=1; i<=m; i++)
  {
    int f,g,w;
    cin>>f>>g>>w; 
    addedge(f,g,w); //建图,有向图连一次边就可以了
  }
  spfa(); //开始跑spfa
  for(int i=1; i<=n; i++)
    if(s==i) cout<<0<<" "; //如果是回到自己,直接输出0
      else cout<<dis[i]<<" "; //否则打印最短距离
  return 0;
}

Djisktra

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int m,n,s,ji,head[200005],dis[200005];
bool bo[200005];
struct node{
    int w,next,yuan;
}ed[200005];
void add(int p,int q,int quan)
{
    ed[++ji].w=quan;
    ed[ji].yuan=q;
    ed[ji].next=head[p];
    head[p]=ji;
}
priority_queue < pair < int , int > > dui;//注意怎么写 
int main(){
    cin>>n>>m>>s;
    for(int i=1;i<=m;i++){
        int cm,cn,cs;
        scanf("%d%d%d",&cm,&cn,&cs);
        add(cm,cn,cs);
    }
    for(int i=1;i<=n;i++)dis[i]=0x7fffffff;//注意是只有初始化 
        dis[s]=0;
        dui.push(make_pair(0,s));//注意make_pair怎么写,内容是什么 
        while(!dui.empty()){//注意有括号 
            int x=dui.top().second;//括号 
            dui.pop();
            if(bo[x])continue;//记得判断重复 
            bo[x]=1;
            for(int j=head[x];j;j=ed[j].next){
                int y=ed[j].yuan,l=dis[x]+ed[j].w;
                if(dis[y]>l){
                    dis[y]=l;
                    dui.push(make_pair(-dis[y],y));//是-dis[y] 
                }
            }
        }
    
    for(int i=1;i<=n;i++)printf("%d ",dis[i]);
    return 0;
}

spfa负环

#include<bits/stdc++.h>
#define IL inline
#define RI register int
#define N 100086
#define rk for(RI i=1;i<=m;i++)
using namespace std;
IL void read(int &x){cin>>x;}
int n,m,T;
struct node{
    int next,yuan,w;
}ed[N];
bool bo[N];
int head[N],ji,dis[N],ans[N];
IL void add(int x,int y,int z){
    ed[++ji].next=head[x];
    ed[ji].yuan=y;
    ed[ji].w=z;
    head[x]=ji;
}
IL bool spfa(int now){
    rk dis[i]=2147483647;
    queue<int>dui;
    dui.push(now);
    bo[now]=1;
    dis[now]=0;
    while(!dui.empty()){
        int x=dui.front();
        dui.pop();
        for(int i=head[x];i;i=ed[i].next){
            int y=ed[i].yuan,l=dis[x]+ed[i].w;
            if(dis[y]>l){
                dis[y]=l;
                ans[y]++;
                dui.push(y);//不用判断是否在队列里面
                bo[y]=1;
                if(ans[y]>=n)return 1;
            }
        }
    }
        return 0;
}
int main(){
    read(T);
    while(T--)
    {
        read(n),read(m);
        
        
        for(RI i=1,cm,cn,cw;i<=m;i++){
            read(cm),read(cn),read(cw);
            if(cw<0)add(cm,cn,cw);
            else add(cm,cn,cw),add(cn,cm,cw);
        }
        if(!spfa(1))cout<<"N0"<<endl;
        else cout<<"YE5"<<endl;
        memset(head,0,sizeof(head));
        memset(bo,0,sizeof(bo));
        memset(ed,0,sizeof(ed));
        memset(ans,0,sizeof(ans));
        memset(head,0,sizeof(head));
        ji=0;
    }
}

最小生成树

#include<bits/stdc++.h>
using namespace std;
struct tree{
    int yuan,next,w;
}ed[200005];
int m,ji,n,head[200005],ans,fa[200005];
bool cmp(tree a,tree b){
    return a.w<b.w;//是< 
}
int find(int k){
    while(k!=fa[k])k=fa[k]=fa[fa[k]];
    return k;
}
void kruskal(){
    sort(ed+1,ed+n+1,cmp);
    for(int i=1;i<=n;i++){
        int x=find(ed[i].next),y=find(ed[i].yuan);
        if(x==y)continue;
        if(x>y){
            fa[y]=x;
        }
        else 
        fa[x]=y;
        ans+=ed[i].w;
        if(++ji==m-1)return ;//n-1即可 
    }
}
int main(){
    cin>>m>>n;
    for(int i=1;i<=n;i++){
        cin>>ed[i].next>>ed[i].yuan>>ed[i].w;//无需链式钱向星,否则yuan不对 
    }
    for(int i=1;i<=m;i++)fa[i]=i;
    ji=0;
    kruskal();
    cout<<ans;
}

LCA

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,s,tot=0,cnt=0;
int head[1000100],nxt[1000100],to[1000100];
int d[500100],f[30][1000100];
int read()
{
    int x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
void addedge(int x,int y)
{
    cnt++;
    nxt[cnt]=head[x];
    head[x]=cnt;
    to[cnt]=y;
}
void dfs(int u,int dep)//处理出各个点的深度
{
    d[u]=dep;
    for(int i=head[u];i!=-1;i=nxt[i])
    {
        int v=to[i];
        if(!d[v]) dfs(v,dep+1),f[0][v]=u;
    }
}
int LCA(int x,int y)
{
    int l=0;
    while((1<<l)<=n) l++;
    l--;//l表示的是最大的i为多少,当然,不用求l也可以,只要是一个够大的数像20即可
    if(d[x]<d[y]) swap(x, y);//让x为深度较大的
    for(int i=20;i>=0;i--)
        if(d[y]<=d[x]-(1<<i)) x=f[i][x];//不断爬树,使深度相同
    if(x==y) return x;
    for(int i=20;i>=0;i--)
    {
        if(f[i][x]!=f[i][y])//不同就一起爬树
        {
            x=f[i][x];
            y=f[i][y];
        }
    }
    return f[0][x];
}
int main()
{
    memset(head,-1,sizeof(head));
    n=read(),m=read(),s=read();
    for(int i=1;i<n;i++)
    {
        int x,y;
        x=read(),y=read();
        addedge(x,y);
        addedge(y,x);
    }
    f[0][s]=s;
    dfs(s,1);
    for(int i=1;(1<<i)<=n;i++)
        for(int j=1;j<=n;j++)
            f[i][j]=f[i-1][f[i-1][j]];//f[i][j] 表示 j的2^i 倍祖先,所以f[0][v]就是v的父亲节点u
    for(int i=1;i<=m;i++)
    {
        int l,r;
        l=read(),r=read();
        printf("%d\n",LCA(l,r));
    }
    return 0;
}

数论模块

线性筛素数

#include<iostream>
using namespace std;
int m,n,prime[10000005],ji;
bool bo[10000005];
int main(){
    cin>>m>>n;
    for(int i=2;i<=m;i++){
        if(bo[i]==0)//不能加括号!!!,每次都要更新!!!
            prime[++ji]=i;
        for(int j=1;i*prime[j]<=m;j++){//记得是prime[j]*i,i和j换个位置
            bo[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
    bo[1]=1,bo[0]=1;
    for(int i=1;i<=n;i++){
        int cn;
        cin>>cn;
        if(bo[cn])cout<<"No"<<endl;
        else cout<<"Yes"<<endl;
    }
}

快速幂

#include<bits/stdc++.h>
using namespace std;
long long m,n,mod;
long long quick(long long b,long long p){
    if(p==0)return 1%mod;//为0才能返回,返回1还要mod 
    long long mid=p/2,bo=p%2;
    long long t=quick(b,mid);
    t=t*t%mod;
    if(bo){
        t=t*b%mod;
    }
    return t;
}
int main(){
    cin>>m>>n>>mod;
    cout<<m<<"^"<<n<<" mod "<<mod<<"="<<quick(m,n);
}

矩阵乘法

 

#include <bits/stdc++.h>
#define ll long long
#define m 1000000007
using namespace std;
inline ll gi(){
    register char ch=getchar();register ll x=0;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return x;
}
ll n,k;
struct node {
    ll mat[100][100];
}add,a,ans,mu,e,qk;
inline node mul(node x,node y){
    node mem=qk;
    for(register int i=1;i<=n;i++){
        for(register int j=1;j<=n;j++){
            for(register int h=1;h<=n;h++){
                mem.mat[i][j]=(mem.mat[i][j]+x.mat[i][h]*y.mat[h][j])%m;
            }
        }
    }
    return mem;
}
inline void quick(ll k){
    ans=e;
    while(k){
        if(k&1)ans=mul(ans,mu);
        mu=mul(mu,mu);
        k>>=1;
    }
}
int main(){
    cin>>n>>k;
    for(register int i=1;i<=n;i++){
        for(register int j=1;j<=n;j++){
            mu.mat[i][j]=a.mat[i][j]=gi();
        }
    }
    for(ll i=1;i<=n;i++){
        e.mat[i][i]=1;
    }
    quick(k);
    for(register int i=1;i<=n;i++){
        for(register int j=1;j<=n;j++){
            printf("%lld ",ans.mat[i][j]);
        }
        printf("\n");
    }
    return 0;
}

乘法逆元

#include<bits/stdc++.h>
using namespace std;
long long n,p,inv[3000001];
int main(){
    cin>>n>>p;
    inv[1]=1;
    printf("1\n");
    for(register long long i=2;i<=n;++i)
    {
        inv[i]=(p-p/i)*inv[p%i]%p;//a*x+b=p,a=[p/x],b=p%a;
        printf("%lld\n",inv[i]);
    }
    return 0;
}

高斯消元

#include<bits/stdc++.h>
using namespace std;
double f[4005][4005],ans[400];
int n;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n+1;j++){
            cin>>f[i][j];
        }
    }
    for(int i=1;i<=n;i++){
        int r=0;
    for(int j=i;j<=n;j++)
            if(fabs(f[r][i])<fabs(f[j][i]))//fabs返回实数的绝对值
                r=j;
        if(!r){
            printf("No Solution");//找不到最大值即此列全为0
            return 0;
        }
        swap(f[i],f[r]);//交换行骚操作~~~
        double chu=f[i][i];//就是此列最大的那个关键元,那整列被放到第i行
        for(int j=i;j<=n+1;j++)f[i][j]/=chu;//是i~n+1!,第1~i为0,本行除以这个关键元
        for(int j=i+1;j<=n;j++){//枚举行数
            chu=f[j][i];//当前行的关键元,要消去,且必须用中间变量(不然在后面的for里面值会被修改) 
            for(int k=i;k<=n+1;k++){//枚举列数,是i~n+1
                f[j][k]-=f[i][k]*chu;//f[i][k]为这一列第一个,用关键元所在行对应列的来消此列其他值
                // if(f[j][k]==-0)f[j][k]=0;
            }
        }
    }
    ans[n]=f[n][n+1];//因为是阶梯型矩阵,最后一行的第n+1个数就是xn的值
    for(int i=n;i>=1;i--){//倒着枚举!
        ans[i]=f[i][n+1];//本行结果初始化为第n+1个数
        for(int j=i+1;j<=n;j++){
           ans[i]-=ans[j]*f[i][j];//ans[j]中已经存放了xj的答案,乘本行第j个再减去就是xi的值
        }
    }
    for(int i=1;i<=n;i++)
        printf("%.2lf\n",ans[i]);
}

欧拉定理

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int n,mod,phi,k;
bool bo;
int quick(int a,int b){
    int res=a,ans=1;
    while(b){
        if(b&1)ans=(long long)ans*res%mod;//要加ll...
        res=(long long)res*res%mod;
        b>>=1;
    }
    return ans%mod;
}
int main(){
    cin>>n>>mod;
    n%=mod;
    int x=phi=mod;//等于mod...
    for(int i=2;i*i<=x;i++){
        if(x%i==0){
            phi=phi/i*(i-1);
            while(x%i==0)x/=i;
        }
    }if(x>1){phi=phi/x*(x-1);}
    char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9'){
        k=(k<<1)+(k<<3)+(ch^48);
        ch=getchar();
        if(k>=phi)bo=1,k%=phi;//>=&&%phi...
    }
    if(k>=phi)bo=1,k%=phi;
    if(bo)k+=phi;
    printf("%d",quick(n,k));
}

Pollard-Rho算法

#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll ans=1;

inline ll quick(ll x,ll p,ll mod){
    ll ans=1;
    while(p){
        if(p&1)ans=ans*x%mod;
        x=x*x%mod; p>>=1;
    }
    return ans;
}

inline bool mr(ll x,ll p){
    if(quick(x,p-1,p)!=1)return 0;
    ll y=p-1,z;
    while(!(y&1)){
        y>>=1; z=quick(x,y,p);
        if(z!=1&&z!=p-1)return 0;
        return 1;
    }return 1;
}

inline bool prime(ll p){ if(p<2)return 0;
    if(p==2||p==3||p==5||p==11||p==101)return 1;
    return mr(2,p)&&mr(3,p)&&mr(5,p)&&mr(11,p)&&mr(101,p);
}


inline ll Abs(ll x){return x<0?-x:x;}
inline ll gcd (ll a,ll b){
    register ll t;
    while (b){
        t=a%b;
        a=b;
        b=t;
    }
    return a;
}

inline ll rho(ll p){
    ll x,y,z,c,g; int i,j;
    while(1){
        x=y=rand()%p; c=rand()%p;
        z=1; i=0; j=1;
        while(++i){
            x=((__int128)x*x+c)%p;
            z=(__int128)z*Abs(y-x)%p;
            if(x==y)break;
            if(z==0){
                g=gcd(Abs(y-x),p);
                if(g>1)return g;
                break;
            }
            if(!(i%127)||i==j){
                g=gcd(z,p);
                if(g>1)return g;
                if(i==j)y=x,j<<=2;
            }
        }
    }
}

inline void find(ll x){
    if(x<=ans)return ;
    if(prime(x)){ans=x;return ;}
    ll p=rho(x);
    while(x%p==0)x/=p;
    find(p); find(x);
}

int main(){
    int t;cin>>t;
    srand(time(0));
    while(t--){
        ll n; ans=1;
        cin>>n; find(n);
        if(ans==n){puts("Prime");continue;}
        printf("%lld\n",ans);
    }
}

NIM博弈

#include<bits/stdc++.h>
using namespace std;
int t,n;
int main(){
    cin>>t;
    while(t--){
        cin>>n;
        int ans=0;
        for(int i=1;i<=n;i++){
            int ci;
            cin>>ci;
            ans^=ci;
        }
        if(ans)cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
}

线性基

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll p[55],a,n,ans;
void merge(ll k){
    for(int i=55;i>=0;i--){//>=0!!!!!!!!
        if(!(k>>i))continue;
        if(!p[i]){p[i]=k;break;}
        k^=p[i];//消去最高位,后面的1不管,这也是为什么线性基不唯一——shuixirui 
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a;
        merge(a);
    }
    for(int i=55;i>=0;i--){
        if((ans^p[i])>ans)ans^=p[i];
    }
    cout<<ans;  
}

ST表

#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000005],f[1000005][21];
int read(){
    int x=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return x;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++){
        f[i][0]=read();
    }
    for(int k=1;k<=20;k++){
        for(int i=1;i<=n-(1<<k)+1;i++){
            f[i][k]=max(f[i][k-1],f[i+(1<<(k-1))][k-1]);//将区间拆成两半[i,i+2^j-1]和[i+2^(j-1),j-1]
        }
    }
    for(int i=1;i<=m;i++){
        int le=read(),ri=read();
        int t=log(ri-le+1)/log(2);//换底公式即log以2为ri-le+1的对数,找到最大的k
        printf("%d\n",max(f[le][t],f[ri-(1<<t)+1][t]));//  左右两半区间查询
    }
    return 0;
}

并查集

#include<bits/stdc++.h>
using namespace std;
int m,n,fa[200005];
int find(int k){
    while(k!=fa[k])k=fa[k]=fa[fa[k]];
    return k;
}
int main(){
    cin>>m>>n;
    for(int i=1;i<=m;i++)fa[i]=i;
    for(int k=1;k<=n;k++){
        int cn,cm,ck;
        cin>>cn>>cm>>ck;
        int a=find(cm),b=find(ck);
        if(cn==1){
            if(a>b)fa[b]=a;
            else fa[a]=b;
        }
        else if(a==b)puts("Y");
            else puts("N");
    }
}

最长公共子序列

#include<iostream>
#include<cstdio>
using namespace std;
int a[100005],b[100005],c[100005],f[100005],n;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        c[a[i]]=i;
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&b[i]);
    }
    int len=0,l,r,mid;
    for(int i=1;i<=n;i++){
        l=0,r=len;
        if(c[b[i]]>f[len]){//
            f[++len]=c[b[i]];//是c[b[i]]!!!
        }
        else{
            while(l!=r){
                mid=(l+r)/2;
                if(f[mid]>c[b[i]]){//是和c[b[i]]比较
                    r=mid;
                }
                else{
                    l=mid+1;//记得+1
                }
            }
            f[l]=min(c[b[i]],f[l]);//记得取min
        }
    }
    cout<<len;
}

数据结构模块

线段树1

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
    ll x=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return x;
}
long long n,m,a[100005];
struct node{
    int le,ri,add;
    ll sum;
}t[100005*4];
inline void build(ll p,ll l,ll r){
    t[p].le=l,t[p].ri=r;
    if(l==r){t[p].sum=a[l];return ;}
    ll mid=(l+r)>>1;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    t[p].sum+=t[p*2].sum+t[p*2+1].sum;
}
inline void spread(ll p){
    if(t[p].add){
        t[p*2].sum+=(ll)(t[p*2].ri-t[p*2].le+1)*t[p].add;
        t[p*2+1].sum+=(ll)(t[p*2+1].ri-t[p*2+1].le+1)*t[p].add;
        t[p*2].add+=t[p].add;
        t[p*2+1].add+=t[p].add;
        t[p].add=0;
    }
}
inline void add(ll p,ll l,ll r,ll k){
    if(t[p].le>=l&&t[p].ri<=r){
        t[p].add+=k;
        t[p].sum+=(ll)(t[p].ri-t[p].le+1)*k;
        return ;
    }
    spread(p);//因为后面t[p].sum还有重新赋值操作所以要下方标记才能保证不变
    register ll mid=(t[p].le+t[p].ri)>>1;
    if(l<=mid)add(p*2,l,r,k);
    if(r>mid)add(p*2+1,l,r,k);
    t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
inline ll query(ll p,ll l,ll r){
    if(t[p].le>=l&&t[p].ri<=r){
        return t[p].sum;
    }
    spread(p);
    register ll val=0,mid=(t[p].le+t[p].ri)>>1;
    if(mid>=l)val+=query(p*2,l,r);
    if(mid<r)val+=query(p*2+1,l,r);
    return val;
}
int main(){
    cin>>n>>m;
    for(register int i=1;i<=n;i++){
        a[i]=read();
    }
    build(1,1,n);
    for(register int i=1;i<=m;i++){
        register int typ=read();
        if(typ==1){
            register int cn=read(),cm=read(),ck=read();
            add(1,cn,cm,ck);
        }
        else {
            register int cn=read(),cm=read();
            cout<<query(1,cn,cm)<<endl;//无论如何都要传入一个原始编号1
        }
    }
}

线段树2

#include <cstdio>
using namespace std;
typedef long long ll;
ll n,m,mod,num,typ,x,y,k,ans;
struct nod
{
    ll l,r,w,add,mul;
}s[1000005];//四倍空间以上
ll build(ll x,ll L,ll R)
{
    s[x]=nod{L,R,0,0,1};//构造函数,用来让代码更简洁
    if(L==R)
    {
        scanf("%lld",&num);
        return s[x].w=num%mod;//特色建树,到了叶子节点时再输入,然后传上去
    }
    ll mid=(L+R)/2;
    return s[x].w=(build(x*2,L,mid)+build(x*2+1,mid+1,R))%mod;
}
void down(ll x)

{//具体的标记下传

    s[x*2].add=(s[x].add+s[x*2].add*s[x].mul)%mod;
    s[x*2+1].add=(s[x].add+s[x*2+1].add*s[x].mul)%mod;
    s[x*2].mul=(s[x*2].mul*s[x].mul)%mod;
    s[x*2+1].mul=(s[x*2+1].mul*s[x].mul)%mod;
    s[x*2].w=(s[x*2].w*s[x].mul+s[x].add*(s[x*2].r-s[x*2].l+1))%mod;
    s[x*2+1].w=(s[x*2+1].w*s[x].mul+s[x].add*(s[x*2+1].r-s[x*2+1].l+1))%mod;
    s[x].add=0;
    s[x].mul=1;
}
ll query(ll x,ll L,ll R)
{
    down(x);
    if(s[x].l>=L&&s[x].r<=R)//包含的话直接返回
        return s[x].w%mod;
    ll mid=(s[x].l+s[x].r)/2;//哪边有询问就加上哪边的询问值
    return ((L<=mid?query(x*2,L,R):0)+(R>mid?query(x*2+1,L,R):0))%mod;
}
void update(ll x,ll v,ll typ,ll L,ll R)
{
    down(x);
    if(typ==1&&s[x].l>=L&&s[x].r<=R)//包含关系
    {
        s[x].mul=(s[x].mul*v)%mod;
        s[x].add=(s[x].add*v)%mod;
        s[x].w=(s[x].w*s[x].mul)%mod;//先乘再加
        return;
    }
    if(typ==2&&s[x].l>=L&&s[x].r<=R)
    {
        s[x].add=(s[x].add+v)%mod;
        s[x].w=(s[x].w+s[x].add*(s[x].r-s[x].l+1))%mod;
        return;
    }
    ll mid=(s[x].l+s[x].r)/2;
    if(L<=mid)
        update(x*2,v,typ,L,R);
    if(R>mid)
        update(x*2+1,v,typ,L,R);
    s[x].w=s[x*2].w+s[x*2+1].w;//最后更新父亲节点
}
main()
{
    scanf("%lld%lld%lld",&n,&m,&mod);
    build(1,1,n);
    for(ll i=1;i<=m;i++)
    {
        scanf("%lld%lld%lld",&typ,&x,&y);
        if(typ!=3)
        {
            scanf("%lld",&k);
            update(1,k,typ,x,y);
        }
        else
            printf("%lld\n",query(1,x,y));
    }
}

猜你喜欢

转载自www.cnblogs.com/lqhsr/p/10884637.html