该题很显然可以发现是一个动态的,如果使用普通差分显然会超时,所以需要实时更新的数据结构这里我们选择二维的树状数组(您要是要用二维线段树我也没啥意见),我们预处理一下,可以在得到右上坐标的同时以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'); } } }