luogu P6224 [BJWC2014]数据 KD-tree 标准板子 重构+二维平面内最近最远距离查询

LINK:数据

这是一个我写过的最标准的板子。

重构什么的写的非常的标准 常数应该也算很小的。

不过虽然过了题 我也不知道代码是否真的无误 反正我已经眼查三遍了...

重构:建议先插入 插入过程中找到第一个不平衡的点再重构。

最小距离查询剪枝:当前坐标为mn和mx中间的时候显然 最小距离可能为0 否则 为他们其中之一和当前坐标的差。

最大距离查询剪枝:当前坐标和mn以及mx的最大距离差。

const int MAXN=500010,K=2;
const db alpha=0.75;
int n,root,top,D,Q,cnt,ans;
struct wy
{
	int d[K];
	int mn[K],mx[K];
	int sz,l,r;
}t[MAXN];
int q[MAXN];
inline int cmp(int a,int b){return t[a].d[D]<t[b].d[D];}
inline void update(int x)
{
	sz(x)=sz(l(x))+sz(r(x))+1;
	for(int i=0;i<K;++i)
    {
        if(l(x))t[x].mx[i]=max(t[x].mx[i],t[l(x)].mx[i]),t[x].mn[i]=min(t[x].mn[i],t[l(x)].mn[i]);
        if(r(x))t[x].mx[i]=max(t[x].mx[i],t[r(x)].mx[i]),t[x].mn[i]=min(t[x].mn[i],t[r(x)].mn[i]);
    }
}
inline int build(int l,int r,int k)
{
	if(l>r)return 0;
	int mid=(l+r)>>1;D=k;
	nth_element(q+l,q+mid,q+1+r,cmp);
	int x=q[mid];
	for(int i=0;i<K;++i)t[x].mx[i]=t[x].mn[i]=t[x].d[i];
	l(x)=build(l,mid-1,(k+1)%K);
	r(x)=build(mid+1,r,(k+1)%K);
	update(x);return x;
}
inline void erase(int x)
{
	if(!x)return;q[++top]=x;
	erase(l(x));erase(r(x));
}
inline void rebuild(int &x,int k)
{
	top=0;erase(x);
	x=build(1,top,k);
}
inline void insert(int &p,int k,int flag)
{
	if(!p)
	{
		p=++cnt;sz(p)=1;
		for(int i=0;i<K;++i)t[p].mx[i]=t[p].mn[i]=t[p].d[i]=q[i];
		return;
	}
	int mark=0;
	if(q[k]<t[p].d[k])
	{
		if((sz(l(p))+1)>=alpha*(sz(p)+1))mark=1;
		insert(l(p),(k+1)%K,flag|mark);
	}
	else
	{
		if((sz(r(p)+1)>=alpha*(sz(p)+1)))mark=1;
		insert(r(p),(k+1)%K,flag|mark);
	}
	if(!flag&&mark)rebuild(p,k);
	update(p);
}
inline int dis(int x)
{
	int cnt=0;
	rep(0,K-1,i)cnt+=abs(t[x].d[i]-q[i]);
	return cnt;
}
inline int dismin(int x)//查当前离节点最近的距离
{
	int cnt=0;
	rep(0,K-1,i)if(q[i]<t[x].mn[i])cnt+=t[x].mn[i]-q[i];
	else if(q[i]>t[x].mx[i])cnt+=q[i]-t[x].mx[i];
	return cnt;
}
inline void ask_min(int x)
{
	ans=min(ans,dis(x));
	int L=dismin(l(x));
	int R=dismin(r(x));
	if(L<R)
	{
		if(L<ans&&l(x))ask_min(l(x));
		if(R<ans&&r(x))ask_min(r(x));
	}
	else
	{
		if(R<ans&&r(x))ask_min(r(x));
		if(L<ans&&l(x))ask_min(l(x));
	}
}
inline int dismax(int x)
{
	int cnt=0;
	rep(0,K-1,i)cnt+=max(abs(q[i]-t[x].mn[i]),abs(q[i]-t[x].mx[i]));
	return cnt;
}
inline void ask_max(int x)
{
	ans=max(ans,dis(x));
	int L=dismax(l(x));
	int R=dismax(r(x));
	if(L>R)
	{
		if(L>ans&&l(x))ask_max(l(x));
		if(R>ans&&r(x))ask_max(r(x));
	}
	else
	{
		if(R>ans&&r(x))ask_max(r(x));
		if(L>ans&&l(x))ask_max(l(x));
	}
}
int main()
{
	freopen("1.in","r",stdin);
	get(n);cnt=n;
	rep(1,n,i)
	{
		int get(x);int get(y);
		t[i].d[0]=x;t[i].d[1]=y;
		q[i]=i;
	}
	root=build(1,n,0);
	get(Q);
	rep(1,Q,i)
	{
		int op;
		get(op);get(q[0]);get(q[1]);
		if(op==0)insert(root,0,0);
		if(op==1)
		{
			ans=INF;
			ask_min(root);
			put(ans);
		}
		if(op==2)
		{
			ans=-INF;
			ask_max(root);
			put(ans);
		}
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/chdy/p/12727807.html