KDT总结

咕咕咕。

学会了一点了。

KDT维护了\(k\)维空间中的超长方体。每个结点及其子树都在同一超长方体中。

KDT的实现与平衡树类似(其实在\(k=1\)时就是另类的平衡树,只不过不太优秀)。树上的每个结点都对应着\(k\)维空间中的一个点。然后随便维护一下信息就可以支持\(k\)维超长方体查询信息了。

还有类似线段树写法,用叶子存信息再向上合并的,但我只写过平衡树写法的。

建树时交替选择\(k\)个维度,每次把处于当前维度的中位数的元素拿出来(使用nth_element,这一步是\(O(n)\)的),再向左右递归。也可以用方差来判断选哪个维度,但感觉不太好写。

插入结点可以二进制分组。具体而言,保证维护的KDT的大小都为\(2^n\),于是插入结点就视作新建了一棵大小为\(1\)的KDT,然后依次将大小相同的KDT合并起来就好(实现的时候就是依次暴力展开然后暴力重构)。也可以根号重构/替罪羊树式重构,复杂度差不多的。

删除可以打标记惰性删除,然后根号/替罪羊重构。

每个结点维护每个维度的最大值与最小值,然后查询随便写一下就好(二进制分组的写法要在每棵树上都查一下)。

建树\(O(n\log n)\),查询\(O(n^{1-\frac{1}{k}})\),插入总的均摊是\(O(n\log^2 n)\)的(二进制分组)/\(O(n\sqrt{n\log n})\)(根号/替罪羊重构)。

OI中\(k=2\)的情况最多,但是还是可以考虑CDQ/树套树。当\(k=3\)时,要谨慎选择KDT,因为查一次就是\(O(n^{\frac{2}{3}})\)

而当\(k\ge 4\)时,还是放弃KDT跑路吧。

为数不多还在坚持KDT的KDT板子题P4148 简单题

板子
#include<bits/stdc++.h>

using namespace std;

const int maxn=2e5+10,mxlg=19;
int n,cnt,lst,b[maxn],rt[mxlg],lim[2][2];
struct TREE{
	int x[2],v,sum,ls,rs,l[2],r[2];
}t[maxn];

bool cmp0(int a,int b){
	return t[a].x[0]<t[b].x[0];
}

bool cmp1(int a,int b){
	return t[a].x[1]<t[b].x[1];
}

#define ls(k) (t[k].ls)
#define rs(k) (t[k].rs)

void pushup(int k){
	t[k].sum=t[k].v+t[ls(k)].sum+t[rs(k)].sum;
	for(int i=0;i<2;++i){
		t[k].l[i]=t[k].r[i]=t[k].x[i];
		if(ls(k)){
			t[k].l[i]=min(t[k].l[i],t[ls(k)].l[i]);
			t[k].r[i]=max(t[k].r[i],t[ls(k)].r[i]);
		}
		if(rs(k)){
			t[k].l[i]=min(t[k].l[i],t[rs(k)].l[i]);
			t[k].r[i]=max(t[k].r[i],t[rs(k)].r[i]);
		}
	}
}
int build(int l,int r,int k){
	int p=(l+r)>>1;
	if(k) nth_element(b+l,b+p,b+r+1,cmp1);
	else nth_element(b+l,b+p,b+r+1,cmp0);
	int x=b[p];
	if(l<p) t[x].ls=build(l,p-1,k^1);
	if(p<r) t[x].rs=build(p+1,r,k^1);
	pushup(x);
	return x;
}

void flatten(int &p){
	if(!p) return;
	b[++cnt]=p;
	flatten(ls(p));
	flatten(rs(p));
	p=0;
}

int qry(int p){
	if(!p) return 0;
	bool flag=true;
	for(int k=0;k<2;++k) flag&=(lim[k][0]<=t[p].l[k]&&t[p].r[k]<=lim[k][1]);
	if(flag) return t[p].sum;
	for(int k=0;k<2;++k){
		if(t[p].l[k]>lim[k][1]||t[p].r[k]<lim[k][0]) return 0;
	}
	int rs=0;
	flag=true;
	for(int k=0;k<2;++k) flag&=(lim[k][0]<=t[p].x[k]&&t[p].x[k]<=lim[k][1]);
	if(flag) rs=t[p].v;
	return rs+=qry(ls(p))+qry(rs(p));
}

int main(){
	scanf("%d",&n);
	n=0;
	while(true){
		int op;
		scanf("%d",&op);
		if(op==3) break;
		else if(op==1){
			int x,y,a;
			scanf("%d%d%d",&x,&y,&a);
			x^=lst;
			y^=lst;
			a^=lst;
			t[++n].x[0]=x;
			t[n].x[1]=y;
			t[n].v=a;
			cnt=1;
			b[1]=n;
			for(int sz=0;;sz++){
				if(!rt[sz]){
					rt[sz]=build(1,cnt,0);
					break;
				}
				else flatten(rt[sz]);
			}
		}	
		else if(op==2){
			scanf("%d%d%d%d",&lim[0][0],&lim[1][0],&lim[0][1],&lim[1][1]);
			lim[0][0]^=lst;
			lim[0][1]^=lst;
			lim[1][0]^=lst;
			lim[1][1]^=lst;
			lst=0;
			for(int i=0;i<mxlg;++i) lst+=qry(rt[i]);
			printf("%d\n",lst);
		}
	}
	return 0;
} 
posted @ 2024-12-23 16:27  RandomShuffle  阅读(38)  评论(0)    收藏  举报