题解:
前一题不是强制在线,后一题是强制在线
树套树空间会炸
说一下cdq分治+树状数组
首先我们利用cdq分治使得查询和操作保证先后关系
然后矩阵查询变成4个矩阵的差
那么我们就可以运用扫描线的方法来维护了
时间nlogn^2,空间O(n)
后一题是kd-tree
查询的方法和线段树基本一样
如果矩阵被包含就返回答案,如果不被包含就直接退出
否则递归下去
然后修改的话和替罪羊树一样
达到一定时候就重构
注意一下x相同insert和build要保证y的顺序区分左右
另外学习了一下map中用struct作为key的方法 虽然这题完全不用用
代码:
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) #define mid ((h+t)/2) #define me(x) memset(x,0,sizeof(x)) const int INF=2e9; const int N=6e6+1e4; char ss[1<<24],*A=ss,*B=ss; IL char gc() { return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++; } template<class T>void read(T &x) { rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48); while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; } IL void umax(int &x,int y) { if (x<y) x=y; } IL void umin(int &x,int y) { if (x>y) x=y; } struct re{ int d[2],v; }p[N]; int cmp_d,ans,rt,num; bool cmp(re x,re y) { return x.d[cmp_d]<y.d[cmp_d]||(x.d[cmp_d]==y.d[cmp_d]&&x.d[cmp_d^1]<y.d[cmp_d^1]); } struct kd { int Mx[N],My[N],Nx[N],Ny[N],count2[N],ls[N],rs[N]; IL void clear() { me(count2); me(ls); me(rs); } IL void updata(int x) { count2[x]=count2[ls[x]]+count2[rs[x]]+p[x].v; if (ls[x]) { umax(Mx[x],Mx[ls[x]]); umax(My[x],My[ls[x]]); umin(Nx[x],Nx[ls[x]]); umin(Ny[x],Ny[ls[x]]); } if (rs[x]) { umax(Mx[x],Mx[rs[x]]); umax(My[x],My[rs[x]]); umin(Nx[x],Nx[rs[x]]); umin(Ny[x],Ny[rs[x]]); } } int build(int h,int t,int o) { cmp_d=o; nth_element(p+h,p+mid,p+t+1,cmp); int x=mid; Mx[x]=Nx[x]=p[x].d[0]; My[x]=Ny[x]=p[x].d[1]; count2[x]=p[x].v; if (h!=x) ls[x]=build(h,mid-1,o^1); else ls[x]=0; if (x!=t) rs[x]=build(mid+1,t,o^1); else rs[x]=0; updata(x); return x; } void insert(int &k,int x,int y,int z,int o) { if (!k) { k=++num; Mx[num]=Nx[num]=p[num].d[0]; My[num]=Ny[num]=p[num].d[1]; count2[num]=p[num].v=z; return; } if (p[k].d[0]==x&&p[k].d[1]==y) { count2[k]+=z; p[k].v+=z; return; } if (!o) if (x<p[k].d[0]||(x==p[k].d[0]&&y<p[k].d[1])) insert(ls[k],x,y,z,o^1); else insert(rs[k],x,y,z,o^1); else if (y<p[k].d[1]||(y==p[k].d[1]&&x<p[k].d[0])) insert(ls[k],x,y,z,o^1); else insert(rs[k],x,y,z,o^1); updata(k); } void query(int k,int x1,int x2,int y1,int y2) { if (!k||Mx[k]<x1||Nx[k]>x2||My[k]<y1||Ny[k]>y2) return; if (x2>=Mx[k]&&Nx[k]>=x1&&y2>=My[k]&&Ny[k]>=y1) { ans+=count2[k]; return; } if (x1<=p[k].d[0]&&p[k].d[0]<=x2&&y1<=p[k].d[1]&&p[k].d[1]<=y2) ans+=p[k].v; query(ls[k],x1,x2,y1,y2); query(rs[k],x1,x2,y1,y2); } }kd; struct re1{ int a,b; }; struct cmp2 { bool operator() (const re1 x,const re1 y) { if (x.a<y.a||(x.a==y.a&&x.b<y.b)) return(1); else return(0); } }; map<re1,int,cmp2> M; int main() { int m; freopen("1.in","r",stdin); freopen("1.out","w",stdout); read(m); int cnt=0,rt=0,i=0; while (1) { i++; ans=0; int k; read(k); if (k==3) break; if (k==1) { int x,y,z; read(x); read(y); read(z); x^=ans; y^=ans; z^=ans; re1 k3=(re1){x,y}; int kk=M[k3]; if (!kk) p[num+1].d[0]=x,p[num+1].d[1]=y,kk=num+1; M[k3]=kk; kd.insert(rt,x,y,z,0); cnt++; if (cnt%10000==0) { kd.clear(); rt=kd.build(1,num,0); } } else { int x1,x2,y1,y2; read(x1),read(y1),read(x2),read(y2); x1^=ans,x2^=ans,y1^=ans,y2^=ans; ans=0; kd.query(rt,x1,x2,y1,y2); cout<<ans<<endl; } } return 0; }