bzoj4066: 简单题

这是一道KD-tree裸题,空间20M。

KD-tree插入点可能会导致树不平衡,使层数过高TLE,因此可以使用替罪羊树暴力重构的思想,同时由于查询较慢,平衡因子可适当减小,具体见代码。另外还有一种每插入若干点暴力重构全树的方法,但好像有点慢?

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200005
#define B 0.63
using namespace std;
int n,p,Ans,D,Q[4],Rt,m,cnt,h[N];
struct KD_node{int d[2],Mx[2],Mn[2],size,sum,ls,rs,val;}T[N];
int R()
{
	char c=getchar();int x=0;
	while(c<'0'||c>'9')c=getchar();
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
void Min(int &x,int &y){if(y<x)x=y;}
void Max(int &x,int &y){if(y>x)x=y;}
bool cmp(const int &x,const int &y){return T[x].d[D]<T[y].d[D];}
void update(int k)
{
	int l=T[k].ls,r=T[k].rs;
	T[k].sum=T[l].sum+T[r].sum+T[k].val;
	T[k].size=T[l].size+T[r].size+1;
	for (int i=0;i<2;i++)
	{
		if(l)Max(T[k].Mx[i],T[l].Mx[i]),Min(T[k].Mn[i],T[l].Mn[i]);
		if(r)Max(T[k].Mx[i],T[r].Mx[i]),Min(T[k].Mn[i],T[r].Mn[i]);
	}
}
void build(int &k,int l,int r,int now)
{
	int mid=(l+r)>>1;D=now;
	nth_element(h+l,h+mid,h+r+1,cmp);
	k=h[mid];T[k].sum=T[k].val;
	for (int i=0;i<2;i++)
		T[k].Mx[i]=T[k].Mn[i]=T[k].d[i];
	if (l<mid) build(T[k].ls,l,mid-1,now^1);
	if (r>mid) build(T[k].rs,mid+1,r,now^1);
	update(k);
}
void del(int &k)
{
	if (!k) return;
	h[++cnt]=k;del(T[k].ls);del(T[k].rs);k=0;
}
void rebuild(int &k,int now)
{
	h[cnt=1]=++m;T[m].size=1;
	for (int i=0;i<2;i++)
		T[m].d[i]=T[m].Mx[i]=T[m].Mn[i]=Q[i];
	T[m].sum=T[m].val=Q[2];
	del(k);build(k,1,cnt,now);
}
void ins(int &k,int now)
{
	if (!k)
	{
		k=++m;T[k].size=1;
		for (int i=0;i<2;i++)
			T[k].d[i]=T[k].Mx[i]=T[k].Mn[i]=Q[i];
		T[k].sum=T[k].val=Q[2];
		return;
	}
	if (Q[now]<T[k].d[now])
		if (T[T[k].ls].size>T[k].size*B) rebuild(k,now);
		else ins(T[k].ls,now^1);
	else
		if (T[T[k].rs].size>T[k].size*B) rebuild(k,now);
		else ins(T[k].rs,now^1);
	update(k);
}
bool inter(int k)
{
	if (!k) return 0;
	return Q[0]<=T[k].Mx[0]&&T[k].Mn[0]<=Q[2]&&Q[1]<=T[k].Mx[1]&&T[k].Mn[1]<=Q[3];
}
void qry(int k)
{
	if (Q[0]<=T[k].Mn[0]&&T[k].Mx[0]<=Q[2]&&Q[1]<=T[k].Mn[1]&&T[k].Mx[1]<=Q[3])
	{
		Ans+=T[k].sum;return;
	}
	if (Q[0]<=T[k].d[0]&&T[k].d[0]<=Q[2]&&Q[1]<=T[k].d[1]&&T[k].d[1]<=Q[3])
		Ans+=T[k].val;
	if (inter(T[k].ls)) qry(T[k].ls);
	if (inter(T[k].rs)) qry(T[k].rs);
}
int main()
{
	for (n=R(),p=R();p!=3;p=R())
	{
		if (p==1) Q[0]=R()^Ans,Q[1]=R()^Ans,Q[2]=R()^Ans,ins(Rt,0);
		else Q[0]=R()^Ans,Q[1]=R()^Ans,Q[2]=R()^Ans,Q[3]=R()^Ans,Ans=0,qry(Rt),printf("%d\n",Ans);
	}
	return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值