因为x<=60所以可以建立60颗线段树,这些线段树是区间赋值,然后再建立一颗记录答案的线段树,每当第一颗线段树上发生推平操作的时候,第二颗线段树也进行更新,当推平不了的时候暴力下方。

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using i128=__int128;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using db = double;
using ldb = long double;
#define F first
#define S second
#define debug(x) cerr<<#x<<":"<<x<<"\n";
#define debugv(v) cerr<<#v<<":\n";for(int i=1;i<v.size();i++) cerr<<v[i]<<" ";cout<<"\n";
const int N=3e5+10;
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
pii operator+(const pii x,const pii y){
    if(x.F==y.F) return {x.F,x.S+y.S};
    if(x.F>y.F) return x;
    return y;
}
struct segtree2{
    struct node{
        int l,r,tag;
        pii num;
    }t[N<<2];
    segtree2(){
        build(1,1,3e5);
    }
    void pushup(int p){
        t[p].num=t[ls(p)].num+t[rs(p)].num;
    }
    void build(int p,int l,int r){
        t[p].l=l,t[p].r=r;
        if(l==r){
            t[p].tag=0;
            t[p].num={0,1};
            return;
        }
        int mid=(l+r)>>1;
        build(ls(p),l,mid);
        build(rs(p),mid+1,r);
        pushup(p);
    }
    void addtag(int p,int d){
        t[p].tag+=d;
        t[p].num.F+=d;
    }
    void pushdown(int p){
        if(t[p].tag){
            addtag(ls(p),t[p].tag);
            addtag(rs(p),t[p].tag);
            t[p].tag=0;
        }
    }
    pii query(int l,int r,int p){
        if(l<=t[p].l&&t[p].r<=r){
            return t[p].num;
        }
        pushdown(p);
        int mid=(t[p].l+t[p].r)>>1;
        pii ans={0,0};
        if(l<=mid) ans=ans+query(l,r,ls(p));
        if(mid<r) ans=ans+query(l,r,rs(p));
        return ans;
    }
    void update(int l,int r,int p,int d){
        if(l<=t[p].l&&t[p].r<=r){
            addtag(p,d);
            return;
        }
        pushdown(p);
        int mid=(t[p].l+t[p].r)>>1;
        if(l<=mid) update(l,r,ls(p),d);
        if(mid<r) update(l,r,rs(p),d);
        pushup(p);
    }
}seg; 
struct segtree1{
    struct node{
        int l,r,num,tag;
    }t[N<<2];
    segtree1(){
        build(1,1,3e5);
    }
    void pushup(int p){
        t[p].num=t[ls(p)].num+t[rs(p)].num;
    }
    void build(int p,int l,int r){
        t[p].l=l,t[p].r=r;
        if(l==r){
            t[p].num=t[p].tag=0;
            return;
        }
        int mid=(l+r)>>1;
        build(ls(p),l,mid);
        build(rs(p),mid+1,r);
        pushup(p);
    }
    void addtag(int p,int d){
        t[p].tag+=d;
        t[p].num+=d*(t[p].r-t[p].l+1);
    }
    void pushdown(int p){
        if(t[p].tag){
            addtag(ls(p),t[p].tag);
            addtag(rs(p),t[p].tag);
            t[p].tag=0;
        }
    }
    void update(int l,int r,int p,int d){
        if(l<=t[p].l&&t[p].r<=r){
            if(d==1){
                if(t[p].num==t[p].r-t[p].l+1){return;}
                else if(t[p].num==0){addtag(p,d);seg.update(t[p].l,t[p].r,1,1);return;}
            }else{
                if(t[p].num==t[p].r-t[p].l+1){addtag(p,d);seg.update(t[p].l,t[p].r,1,-1);return;}
                else if(t[p].num==0){return;}
            }
        }
        pushdown(p);
        int mid=(t[p].l+t[p].r)>>1;
        if(l<=mid) update(l,r,ls(p),d);
        if(mid<r) update(l,r,rs(p),d);
        pushup(p);
    }
}t1[61];
void solve(){
    int n,q;cin>>n>>q;
    while(q--){
        int op;cin>>op;
        if(op==1){
            int l,r,x;cin>>l>>r>>x;
            t1[x].update(l,r,1,1);
        }else if(op==2){
            int l,r,x;cin>>l>>r>>x;
            t1[x].update(l,r,1,-1);
        }else{
            int l,r;cin>>l>>r;
            pii ans=seg.query(l,r,1);
            cout<<ans.F<<" "<<ans.S<<"\n";
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int t=1;
    // cin>>t;
    while(t--) solve();
    return 0;
}