bzoj 4066: 简单题 k-d tree

       这道题目由于空间为20M因此只能使用k-d tree。由于在线插入可能会导致不平衡,因此需要使用替罪羊树的思想暴力重构,保证时间复杂度。由于k-d tree是查询大于插入的,因此可以把平衡因子设的小一点(代码中的0.7还是不够小)。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define N 200005
using namespace std;

int tot,cnt,rt,sx,sy,tx,ty,dms,ans,h[N];
int read(){
	int x=0; char ch=getchar();
	while (ch<'0' || ch>'9') ch=getchar();
	while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
	return x;
}
void up(int &u,int v){ if (u<v) u=v; }
void dn(int &u,int v){ if (u>v) u=v; }
struct node{
	int d[2],x[2],y[2],ls,rs,sum,val,sz,dc;
	void pfs(int u,int v,int w){
		x[0]=x[1]=d[0]=u; y[0]=y[1]=d[1]=v;
		sum=val=w; sz=1;
	}
	void clr(){
		x[0]=x[1]=d[0]; y[0]=y[1]=d[1]; ls=rs=0;
		sum=val; sz=1;
	}
}p[N];
bool cmp(int x,int y){ return p[x].d[dms]<p[y].d[dms]; }
struct kd_tree{
	void maintain(int k,int t){
		p[k].sum+=p[t].sum; p[k].sz+=p[t].sz;
		dn(p[k].x[0],p[t].x[0]); up(p[k].x[1],p[t].x[1]);
		dn(p[k].y[0],p[t].y[0]); up(p[k].y[1],p[t].y[1]);
	}
	void del(int k){
		h[++cnt]=k;
		if (p[k].ls) del(p[k].ls); if (p[k].rs) del(p[k].rs);
	}
	void build(int &k,int l,int r,int now){
		int mid=(l+r)>>1; dms=now;
		nth_element(h+l,h+mid,h+r+1,cmp); k=h[mid];
		p[k].clr(); p[k].dc=now;
		if (l<mid){ build(p[k].ls,l,mid-1,now^1); maintain(k,p[k].ls); }
		if (mid<r){ build(p[k].rs,mid+1,r,now^1); maintain(k,p[k].rs); }
	}
	void ins(int &k,int np){
		if (!k){ k=np; p[k].dc=rand()&1; return; }
		maintain(k,np); dms=p[k].dc;
		if (p[np].d[dms]<p[k].d[dms])
			if (p[p[k].ls].sz>p[k].sz*0.7){
				h[cnt=1]=np; del(k); build(k,1,cnt,dms);
			} else ins(p[k].ls,np);
		else
			if (p[p[k].rs].sz>p[k].sz*0.7){
				h[cnt=1]=np; del(k); build(k,1,cnt,dms);
			} else ins(p[k].rs,np);
	}
	bool ok(int k){
		return p[k].x[0]<=tx && p[k].x[1]>=sx && p[k].y[0]<=ty && p[k].y[1]>=sy;
	}
	void qry(int k){
		if (sx<=p[k].x[0] && p[k].x[1]<=tx && sy<=p[k].y[0] && p[k].y[1]<=ty){
			ans+=p[k].sum; return;
		}
		if (sx<=p[k].d[0] && p[k].d[0]<=tx && sy<=p[k].d[1] && p[k].d[1]<=ty) ans+=p[k].val;
		if (p[k].ls && ok(p[k].ls)) qry(p[k].ls);
		if (p[k].rs && ok(p[k].rs)) qry(p[k].rs);
	}
}kd;
int main(){
	srand(20160414);
	int cas,x=read()>>1,y; tot=rt=1; p[1].pfs(x,x,0);
	for (cas=read(); cas!=3; cas=read())
		if (cas==1){
			x=read()^ans; y=read()^ans; p[++tot].pfs(x,y,read()^ans);
			kd.ins(rt,tot);
		} else{
			sx=read()^ans; sy=read()^ans; tx=read()^ans; ty=read()^ans;
			ans=0; kd.qry(rt); printf("%d\n",ans);
		}
	return 0;
}


by lych

2016.4.14

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值