luogu P4148 简单题
题面传送门
这里有一只不会KDT的大sb。
建树
如果只有一个点,肯定是直接这个点就行。
否则选取一个维度,并选取这个维度上的一个点,将剩下的点按照这个维度的坐标分成左右两个部分。这样我们实现了将一个超长方体分成两个超长方体的结构,这样可以递归建树。
但是这样的问题在于可能是\(O(n^2)\)的就非常逊。
容易想到仿效线段树,每次取出的一个维度的点的坐标为当前维度的中位数,这样树高是\(O(\log n)\)的。
但是可能这个维度全部堆在一个坐标上,所以我们每次选取方差最大的维度进行划分,这样如果没有重复的点的话树高一定是\(O(\log n)\)
但是还有一个问题就是每次建树要选出当前的中位数,如果用sort复杂度直接变成\(O(n\log^2n)\)非常逊。快排有一个期望\(O(n)\)求\(n\)个数中第\(\frac{n}{2}\)小的方法:每次随机选取一个数,将大于这个数的放右边,小于这个数的放左边,然后选取\(\frac{n}{2}\)在的一边递归,期望复杂度为\(\sum\limits{\frac{n}{2^i}}=O(n)\)。STL中有nth_element
函数与此功能相同。
插入
直接插入即可,看在当前点划分维度的左边还是右边,直接递归下去。然后如果发现一颗子树失衡,直接像替罪羊树一样暴力重构即可。一般取\(\alpha=0.75\)。
查询
直接像四分树那样查询,如果不交就返回0,如果完全包含就直接返回这个区间的答案,否则就继续递归下去。
听说二维情况的时间复杂度为\(O(\sqrt n)\),扩展到\(k\)维的情况下复杂度是\(O(n^{1-\frac{1}{k}})\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (200000+5)
#define M (1<<8)
#define K (6)
#define mod 12345678
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;const db alpha=0.75;
int n,m,k,x,y,z,op,l,r,La,Rt,H;struct Node{int x,y,w;}S[N];
namespace KDT{
int W[N],L[N],R[N],U[N],D[N],ls[N],rs[N],Si[N],op[N],g[N],Gh;I bool C1(int x,int y){return S[x].x<S[y].x;}I bool C2(int x,int y){return S[x].y<S[y].y;}
I void Up(int x){W[x]=W[ls[x]]+W[rs[x]]+S[x].w;Si[x]=Si[ls[x]]+Si[rs[x]]+1;L[x]=R[x]=S[x].x;U[x]=D[x]=S[x].y;ls[x]&&(L[x]=min(L[x],L[ls[x]]),R[x]=max(R[x],R[ls[x]]),U[x]=min(U[x],U[ls[x]]),D[x]=max(D[x],D[ls[x]]));rs[x]&&(L[x]=min(L[x],L[rs[x]]),R[x]=max(R[x],R[rs[x]]),U[x]=min(U[x],U[rs[x]]),D[x]=max(D[x],D[rs[x]]));}
I void print(int x){if(!x) return;print(ls[x]);g[++Gh]=x;print(rs[x]);}I int BD(int l,int r){
if(l>r) return 0;int i,m=l+r>>1;db avx=0,avy=0,vax=0,vay=0;for(i=l;i<=r;i++) avx+=S[g[i]].x,avy+=S[g[i]].y;avx/=r-l+1;avy/=r-l+1;
for(i=l;i<=r;i++) vax+=(S[g[i]].x-avx)*(S[g[i]].x-avx),vay+=(S[g[i]].y-avy)*(S[g[i]].y-avy);nth_element(g+l,g+m,g+r+1,vax>=vay?C1:C2);op[g[m]]=(vax>=vay);ls[g[m]]=BD(l,m-1);rs[g[m]]=BD(m+1,r);return Up(g[m]),g[m];
}I void CK(int &x){max(Si[ls[x]],Si[rs[x]])>Si[x]*alpha&&(Gh=0,print(x),x=BD(1,Gh),0);}
I void Ins(int Id,int &v){if(!v) return v=Id,Up(v);op[v]?(S[Id].x<S[v].x?Ins(Id,ls[v]):Ins(Id,rs[v])):(S[Id].y<S[v].y?Ins(Id,ls[v]):Ins(Id,rs[v]));Up(v);CK(v);}
I int Qry(int x,int y,int l,int r,int v){if(!v||l<L[v]||x>R[v]||y>D[v]||r<U[v]) return 0;if(x<=L[v]&&y<=U[v]&&l>=R[v]&&r>=D[v]) return W[v];return (x<=S[v].x&&y<=S[v].y&&l>=S[v].x&&r>=S[v].y?S[v].w:0)+Qry(x,y,l,r,ls[v])+Qry(x,y,l,r,rs[v]);}
}
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d",&n);while(1){scanf("%d",&op);if(op==3) return 0;
if(op==1) scanf("%d%d%d",&x,&y,&z),x^=La,y^=La,z^=La,S[++H]=(Node){x,y,z},KDT::Ins(H,Rt);
else scanf("%d%d%d%d",&x,&y,&l,&r),x^=La,y^=La,l^=La,r^=La,printf("%d\n",La=KDT::Qry(x,y,l,r,Rt));
}
}