该题很显然可以发现是一个动态的,如果使用普通差分显然会超时,所以需要实时更新的数据结构这里我们选择二维的树状数组(您要是要用二维线段树我也没啥意见),我们预处理一下,可以在得到右上坐标的同时以O(1)的时间获得左下坐标。随后我们需要考虑的便是配对问题,相对于普通差分,我们会在一个数组里面设置一个起始值,一个终止值,可是这样我们便无法讲起始值和终止值区分开,所以我们需要采用两个树状数组对应进行匹配。其次对于二维向量匹配问题,我们只需要一个起始向量,但是想固定一个矩阵,我们需要3个终止向量,注意的是需要让一个起始向量配对3个终止向量,所以我们可以将向量分为一个二维向量信息,即水平向量信息,竖直向量信息。终止信息分为3种,单水平向量信息,单竖直向量信息,即有水平向量信息又有竖直向量信息。然后在配对期间我们采用差分配对的方法进行配对,计算信号数差即可。

#include<bits/stdc++.h>
using namespace std;
const int N=2e3+7;
struct xyz{
    int x,y,z;
    inline xyz operator + (const xyz &a)const{
        return {x+a.x,y+a.y,z+a.z};
    }
    inline xyz operator - (const xyz &a)const{
        return {x-a.x,y-a.y,z-a.z};
    }
};
xyz tr1[N][N],tr2[N][N];
int su[N],vis[N];
int lowit(int x){
    return x&-x;
}
int read(){
    int x=0;char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar());
    for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
    return x;
}
void ptr(int x){
    if(x>9)ptr(x/10);
    putchar(x%10+'0');
}
void oula(){
    vis[1]=1;
    for(int i=2;i<N;i++){
        if(!vis[i])vis[i]=1,su[++su[0]]=i;
        for(int j=1;j<=su[0]&&i*su[j]<N;j++){
            vis[i*su[j]]=i;
            if(i%su[j]==0)break;
        }
    }
}
void add(xyz t[N][N],int x,int y,xyz c){
    for(int a=x;a<N;a+=lowit(a))
        for(int b=y;b<N;b+=lowit(b))
            t[a][b]=t[a][b]+c;
}
xyz sum(xyz t[N][N],int x,int y){
    xyz res={0,0,0};
    for(int a=x;a;a-=lowit(a))
        for(int b=y;b;b-=lowit(b))
            res=res+t[a][b];
    return res;
}
int main(){
    oula();
    int m=read();
    while(m--){
        int k=read(),x,y,x2=read(),y2=read();
        if(k==1){
            x=vis[x2];y=vis[y2];
            add(tr1,x,y,{0,0,1});add(tr2,x2,y2,{0,0,1});add(tr2,x,y2,{0,1,0});add(tr2,x2,y,{1,0,0});
        }
        else{
            x=read(),y=read();
            int res=sum(tr1,x,y).z;
            int res1=sum(tr2,x,y2-1).y+sum(tr2,x2-1,y).x-sum(tr2,x2-1,y2-1).z;
            //cout<<res-res1<<"\n";
            ptr(res-res1);putchar('\n');
        }
    }
}