根据方差进行维度划分
宏定义
- #define ls(p) a[p].tl:KD-Tree 中点 p 的左儿子。
- #define rs(p) a[p].tr:KD-Tree 中点 p 的右儿子。
变量
- const int DE:KD-Tree 的维度为 DE−1。
- int nde:定义在全局的一个维度,用于 cmp 的比较。
- int L[i]:查询时超立方体的左端点。
- int R[i]:查询时超立方体的右端点。
- Node s[p]:存储超立方体中点 p 信息的结构体。
- int s[p].w[i]:超立方体中点 p 的第 i 维坐标。
- int s[p].val:超立方体中点 p 的权值。
- const double A:重构的判定常数。
- int rt:KD-Tree 的根。
- int tot:要重构的节点数。
- int g[i]:要重构的子树中序遍历下的第 i 个点。
- int ans:存储查询时的答案。
- Tree a[p]:KD-Tree 上节点 p 的信息。
- int a[p].tl:节点 p 的左儿子。
- int a[p].tr:节点 p 的右儿子。
- int a[p].de:节点 p 的划分维度。
- int a[p].sz:节点 p 的子树大小。
- int a[p].l[i]:节点 p 子树的第 i 维左端点。
- int a[p].r[i]:节点 p 子树的第 i 维右端点。
- int a[p].mx:节点 p 子树的最大值信息。
函数
- bool cmp(int p,int q):比较点 p 和 q 在 nde 维度的大小。
- void dfs(int p):中序遍历以 p 为根的子树,将顺序存入 g 数组。
- void update(int p,int son,int de):用节点 p 的孩子 son 的第 de 维更新 p。
- void pushup(int p):上传信息。
- double fangc(int l,int r,int de):求 [l,r] 的点按维度 de 划分时的方差。
- int build(int l,int r):对区间 [l,r] 按方差最大的维度划分。
- void rebuild(int &p):重建以 p 为根的子树。
- bool bad(int p):判断是否需要重构。
- void insert(int &p,int x):在以 p 为根的子树中插入点 x。
- void query(int p,int *l,int *r):在以点 p 为根的子树内查询超立方体 [l,r] 的答案。
- void change(int p,int x,int val):将以点 p 为根的子树内的点 x 的权值改为 val。
代码
const int DE=4;
int nde,L[DE],R[DE];
struct Node{
int w[DE],val;
}s[N];
bool cmp(int p,int q){
return s[p].w[nde]==s[q].w[nde]?p<q:s[p].w[nde]<s[q].w[nde];
}
#define ls(p) a[p].tl
#define rs(p) a[p].tr
struct KD{
const double A=0.725;
int rt,tot,g[N],ans;
struct Tree{
int tl,tr,de,sz;
int l[DE],r[DE],mx;
}a[N];
void dfs(int p){
if(ls(p))dfs(ls(p));
g[++tot]=p;
if(rs(p))dfs(rs(p));
}
void update(int p,int son,int de){
a[p].l[de]=min(a[p].l[de],a[son].l[de]);
a[p].r[de]=max(a[p].r[de],a[son].r[de]);
}
void pushup(int p){
a[p].sz=a[ls(p)].sz+a[rs(p)].sz+1;
a[p].mx=max(s[p].val,max(a[ls(p)].mx,a[rs(p)].mx));
for(int i=1;i<DE;i++)a[p].l[i]=a[p].r[i]=s[p].w[i];
if(ls(p))for(int i=1;i<DE;i++)update(p,ls(p),i);
if(rs(p))for(int i=1;i<DE;i++)update(p,rs(p),i);
}
double fangc(int l,int r,int de){
double av=0,sa=0;
for(int i=l;i<=r;i++)av+=s[g[i]].w[de];
av/=double(r-l+1);
for(int i=l;i<=r;i++)
sa+=(av-s[g[i]].w[de])*(av-s[g[i]].w[de]);
return sa;
}
int build(int l,int r){
if(l>r)return 0;
int p=(l+r)>>1;
double fcm=0,fc;
nde=0;
for(int i=1;i<DE;i++){
fc=fangc(l,r,i);
if(!nde||fcm<fc)
nde=i,fcm=fc;
}
nth_element(g+l,g+p,g+r+1,cmp);
a[g[p]].de=nde;
ls(g[p])=build(l,p-1);rs(g[p])=build(p+1,r);
pushup(g[p]);return g[p];
}
void rebuild(int &p){
tot=0;dfs(p);p=build(1,tot);
}
bool bad(int p){
return a[p].sz*A<=(double)max(a[ls(p)].sz,a[rs(p)].sz);
}
void insert(int &p,int x){
if(!p){
pushup(p=x);return;
}
if(s[x].w[a[p].de]<=s[p].w[a[p].de])
insert(ls(p),x);
else insert(rs(p),x);
pushup(p);
if(bad(p))rebuild(p);
}
void query(int p,int *l,int *r){
if(!p)return;
bool flag1=1,flag2=1;
for(int i=1;i<DE;i++){
if(r[i]<a[p].l[i]||a[p].r[i]<l[i])return;
if(r[i]<a[p].r[i]||a[p].l[i]<l[i])flag1=0;
if(r[i]<s[p].w[i]||s[p].w[i]<l[i])flag2=0;
}
if(flag1){
ans=max(ans,a[p].mx);
return;
}
ans=max(ans,flag2*s[p].val);
if(ans<a[ls(p)].mx)
query(ls(p),l,r);
if(ans<a[rs(p)].mx)
query(rs(p),l,r);
return;
}
void change(int p,int x,int val){
if(p==x){
s[p].val=val;
a[p].mx=max(a[p].mx,s[p].val);return;
}
nde=a[p].de;
if(cmp(x,p))
change(ls(p),x,val);
else change(rs(p),x,val);
a[p].mx=max(a[p].mx,max(a[ls(p)].mx,a[rs(p)].mx));
}
}kd;
根据深度进行维度划分
宏定义
- #define ls(p) a[p].tl:KD-Tree 中点 p 的左儿子。
- #define rs(p) a[p].tr:KD-Tree 中点 p 的右儿子。
变量
- const int DE:KD-Tree 的维度为 DE−1。
- int nde:定义在全局的一个维度,用于 cmp 的比较。
- int L[i]:查询时超立方体的左端点。
- int R[i]:查询时超立方体的右端点。
- Node s[p]:存储超立方体中点 p 信息的结构体。
- int s[p].w[i]:超立方体中点 p 的第 i 维坐标。
- int s[p].val:超立方体中点 p 的权值。
- const double A:重构的判定常数。
- int rt:KD-Tree 的根。
- int tot:要重构的节点数。
- int g[i]:要重构的子树中序遍历下的第 i 个点。
- int ans:存储查询时的答案。
- Tree a[p]:KD-Tree 上节点 p 的信息。
- int a[p].tl:节点 p 的左儿子。
- int a[p].tr:节点 p 的右儿子。
- int a[p].de:节点 p 的划分维度。
- int a[p].sz:节点 p 的子树大小。
- int a[p].l[i]:节点 p 子树的第 i 维左端点。
- int a[p].r[i]:节点 p 子树的第 i 维右端点。
- int a[p].mx:节点 p 子树的最大值信息。
函数
- bool cmp(int p,int q):比较点 p 和 q 在 nde 维度的大小。
- void dfs(int p):中序遍历以 p 为根的子树,将顺序存入 g 数组。
- void update(int p,int son,int de):用节点 p 的孩子 son 的第 de 维更新 p。
- void pushup(int p):上传信息。
- int build(int lde,int l,int r):[l,r] 的父亲的划分维度为 lde,对区间 [l,r] 进行下一维的划分。
- void rebuild(int &p):重建以 p 为根的子树。
- bool bad(int p):判断是否需要重构。
- void insert(int &p,int x):在以 p 为根的子树中插入点 x。
- void query(int p,int *l,int *r):在以点 p 为根的子树内查询超立方体 [l,r] 的答案。
- void change(int p,int x,int val):将以点 p 为根的子树内的点 x 的权值改为 val。
代码
const int DE=4;
int nde,L[DE],R[DE];
struct Node{
int w[DE],val;
}s[N];
bool cmp(int p,int q){
return s[p].w[nde]==s[q].w[nde]?p<q:s[p].w[nde]<s[q].w[nde];
}
#define ls(p) a[p].tl
#define rs(p) a[p].tr
struct KD{
const double A=0.725;
int rt,tot,g[N],ans;
struct Tree{
int tl,tr,de,sz;
int l[DE],r[DE],mx;
}a[N];
void dfs(int p){
if(ls(p))dfs(ls(p));
g[++tot]=p;
if(rs(p))dfs(rs(p));
}
void update(int p,int son,int de){
a[p].l[de]=min(a[p].l[de],a[son].l[de]);
a[p].r[de]=max(a[p].r[de],a[son].r[de]);
}
void pushup(int p){
a[p].sz=a[ls(p)].sz+a[rs(p)].sz+1;
a[p].mx=max(s[p].val,max(a[ls(p)].mx,a[rs(p)].mx));
for(int i=1;i<DE;i++)a[p].l[i]=a[p].r[i]=s[p].w[i];
if(ls(p))for(int i=1;i<DE;i++)update(p,ls(p),i);
if(rs(p))for(int i=1;i<DE;i++)update(p,rs(p),i);
}
int build(int lde,int l,int r){
if(l>r)return 0;
int p=(l+r)>>1;
nde=(lde==3?1:lde+1);
nth_element(g+l,g+p,g+r+1,cmp);
a[g[p]].de=nde;
ls(g[p])=build(a[g[p]].de,l,p-1);
rs(g[p])=build(a[g[p]].de,p+1,r);
pushup(g[p]);return g[p];
}
void rebuild(int &p){
tot=0;dfs(p);p=build(1,1,tot);
}
bool bad(int p){
return a[p].sz*A<=(double)max(a[ls(p)].sz,a[rs(p)].sz);
}
void insert(int &p,int x){
if(!p){
pushup(p=x);return;
}
if(s[x].w[a[p].de]<=s[p].w[a[p].de])
insert(ls(p),x);
else insert(rs(p),x);
pushup(p);
if(bad(p))rebuild(p);
}
void query(int p,int *l,int *r){
if(!p)return;
bool flag1=1,flag2=1;
for(int i=1;i<DE;i++){
if(r[i]<a[p].l[i]||a[p].r[i]<l[i])return;
if(r[i]<a[p].r[i]||a[p].l[i]<l[i])flag1=0;
if(r[i]<s[p].w[i]||s[p].w[i]<l[i])flag2=0;
}
if(flag1){
ans=max(ans,a[p].mx);
return;
}
ans=max(ans,flag2*s[p].val);
if(ans<a[ls(p)].mx)
query(ls(p),l,r);
if(ans<a[rs(p)].mx)
query(rs(p),l,r);
return;
}
void change(int p,int x,int val){
if(p==x){
s[p].val=val;
a[p].mx=max(a[p].mx,s[p].val);return;
}
nde=a[p].de;
if(cmp(x,p))
change(ls(p),x,val);
else change(rs(p),x,val);
a[p].mx=max(a[p].mx,max(a[ls(p)].mx,a[rs(p)].mx));
}
}kd;