Kd-Tree

根据方差进行维度划分

宏定义

  • #define ls(p) a[p].tl\texttt{\#define ls(p) a[p].tl}KD-Tree\text{KD-Tree} 中点 pp 的左儿子。
  • #define rs(p) a[p].tr\texttt{\#define rs(p) a[p].tr}KD-Tree\text{KD-Tree} 中点 pp 的右儿子。

变量

  • const int DE\texttt{const int DE}KD-Tree\text{KD-Tree} 的维度为 DE1DE-1
  • int nde\texttt{int nde}:定义在全局的一个维度,用于 cmp\text{cmp} 的比较。
  • int L[i]\texttt{int L[i]}:查询时超立方体的左端点。
  • int R[i]\texttt{int R[i]}:查询时超立方体的右端点。
  • Node s[p]\texttt{Node s[p]}:存储超立方体中点 pp 信息的结构体。
  • int s[p].w[i]\texttt{int s[p].w[i]}:超立方体中点 pp 的第 ii 维坐标。
  • int s[p].val\texttt{int s[p].val}:超立方体中点 pp 的权值。
  • const double A\texttt{const double A}:重构的判定常数。
  • int rt\texttt{int rt}KD-Tree\text{KD-Tree} 的根。
  • int tot\texttt{int tot}:要重构的节点数。
  • int g[i]\texttt{int g[i]}:要重构的子树中序遍历下的第 ii 个点。
  • int ans\texttt{int ans}:存储查询时的答案。
  • Tree a[p]\texttt{Tree a[p]}KD-Tree\text{KD-Tree} 上节点 pp 的信息。
  • int a[p].tl\texttt{int a[p].tl}:节点 pp 的左儿子。
  • int a[p].tr\texttt{int a[p].tr}:节点 pp 的右儿子。
  • int a[p].de\texttt{int a[p].de}:节点 pp 的划分维度。
  • int a[p].sz\texttt{int a[p].sz}:节点 pp 的子树大小。
  • int a[p].l[i]\texttt{int a[p].l[i]}:节点 pp 子树的第 ii 维左端点。
  • int a[p].r[i]\texttt{int a[p].r[i]}:节点 pp 子树的第 ii 维右端点。
  • int a[p].mx\texttt{int a[p].mx}:节点 pp 子树的最大值信息。

函数

  • bool cmp(int p,int q)\texttt{bool cmp(int p,int q)}:比较点 ppqqndende 维度的大小。
  • void dfs(int p)\texttt{void dfs(int p)}:中序遍历以 pp 为根的子树,将顺序存入 gg 数组。
  • void update(int p,int son,int de)\texttt{void update(int p,int son,int de)}:用节点 pp 的孩子 sonson 的第 dede 维更新 pp
  • void pushup(int p)\texttt{void pushup(int p)}:上传信息。
  • double fangc(int l,int r,int de)\texttt{double fangc(int l,int r,int de)}:求 [l,r][l,r] 的点按维度 dede 划分时的方差。
  • int build(int l,int r)\texttt{int build(int l,int r)}:对区间 [l,r][l,r] 按方差最大的维度划分。
  • void rebuild(int &p)\texttt{void rebuild(int \&p)}:重建以 pp 为根的子树。
  • bool bad(int p)\texttt{bool bad(int p)}:判断是否需要重构。
  • void insert(int &p,int x)\texttt{void insert(int \&p,int x)}:在以 pp 为根的子树中插入点 xx
  • void query(int p,int *l,int *r)\texttt{void query(int p,int *l,int *r)}:在以点 pp 为根的子树内查询超立方体 [l,r][l,r] 的答案。
  • void change(int p,int x,int val)\texttt{void change(int p,int x,int val)}:将以点 pp 为根的子树内的点 xx 的权值改为 valval

代码

const int DE=4;//3维 
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\texttt{\#define ls(p) a[p].tl}KD-Tree\text{KD-Tree} 中点 pp 的左儿子。
  • #define rs(p) a[p].tr\texttt{\#define rs(p) a[p].tr}KD-Tree\text{KD-Tree} 中点 pp 的右儿子。

变量

  • const int DE\texttt{const int DE}KD-Tree\text{KD-Tree} 的维度为 DE1DE-1
  • int nde\texttt{int nde}:定义在全局的一个维度,用于 cmp\text{cmp} 的比较。
  • int L[i]\texttt{int L[i]}:查询时超立方体的左端点。
  • int R[i]\texttt{int R[i]}:查询时超立方体的右端点。
  • Node s[p]\texttt{Node s[p]}:存储超立方体中点 pp 信息的结构体。
  • int s[p].w[i]\texttt{int s[p].w[i]}:超立方体中点 pp 的第 ii 维坐标。
  • int s[p].val\texttt{int s[p].val}:超立方体中点 pp 的权值。
  • const double A\texttt{const double A}:重构的判定常数。
  • int rt\texttt{int rt}KD-Tree\text{KD-Tree} 的根。
  • int tot\texttt{int tot}:要重构的节点数。
  • int g[i]\texttt{int g[i]}:要重构的子树中序遍历下的第 ii 个点。
  • int ans\texttt{int ans}:存储查询时的答案。
  • Tree a[p]\texttt{Tree a[p]}KD-Tree\text{KD-Tree} 上节点 pp 的信息。
  • int a[p].tl\texttt{int a[p].tl}:节点 pp 的左儿子。
  • int a[p].tr\texttt{int a[p].tr}:节点 pp 的右儿子。
  • int a[p].de\texttt{int a[p].de}:节点 pp 的划分维度。
  • int a[p].sz\texttt{int a[p].sz}:节点 pp 的子树大小。
  • int a[p].l[i]\texttt{int a[p].l[i]}:节点 pp 子树的第 ii 维左端点。
  • int a[p].r[i]\texttt{int a[p].r[i]}:节点 pp 子树的第 ii 维右端点。
  • int a[p].mx\texttt{int a[p].mx}:节点 pp 子树的最大值信息。

函数

  • bool cmp(int p,int q)\texttt{bool cmp(int p,int q)}:比较点 ppqqndende 维度的大小。
  • void dfs(int p)\texttt{void dfs(int p)}:中序遍历以 pp 为根的子树,将顺序存入 gg 数组。
  • void update(int p,int son,int de)\texttt{void update(int p,int son,int de)}:用节点 pp 的孩子 sonson 的第 dede 维更新 pp
  • void pushup(int p)\texttt{void pushup(int p)}:上传信息。
  • int build(int lde,int l,int r)\texttt{int build(int lde,int l,int r)}[l,r][l,r] 的父亲的划分维度为 ldelde,对区间 [l,r][l,r] 进行下一维的划分。
  • void rebuild(int &p)\texttt{void rebuild(int \&p)}:重建以 pp 为根的子树。
  • bool bad(int p)\texttt{bool bad(int p)}:判断是否需要重构。
  • void insert(int &p,int x)\texttt{void insert(int \&p,int x)}:在以 pp 为根的子树中插入点 xx
  • void query(int p,int *l,int *r)\texttt{void query(int p,int *l,int *r)}:在以点 pp 为根的子树内查询超立方体 [l,r][l,r] 的答案。
  • void change(int p,int x,int val)\texttt{void change(int p,int x,int val)}:将以点 pp 为根的子树内的点 xx 的权值改为 valval

代码

const int DE=4;//3维 
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;
posted @ 2023-08-21 15:08  luckydrawbox  阅读(7)  评论(0)    收藏  举报  来源