【BZOJ】【P2648&P2716】【SJY摆棋子】【天使玩偶】【题解】【kdtree】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2648 http://www.lydsy.com/JudgeOnline/problem.php?id=2716

果然kdtree写的太丑了……而且慢的像toushi

似乎是否进入另一颗子树只是一个估价函数?

Code:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cctype>
#include<climits>
#include<cmath>
using namespace std;
const int maxn=500005;
int n,m,D;
int getint(){
	int res=0,f=1;char c=getchar();
	while(!isdigit(c))f=f==-1||c=='-'?-1:1,c=getchar();
	while(isdigit(c))res=res*10+c-'0',c=getchar();
	return res*f;
}
struct point{
	int d[2],mn[2],mx[2],l,r;
	int& operator[](int i){return d[i];}
	bool operator<(point p)const{return d[D]<p[D];}
	point(int _x=0,int _y=0):
		l(0),r(0){d[0]=_x,d[1]=_y;}
}p[maxn];
int dis(point a,point b){return abs(a[0]-b[0])+abs(a[1]-b[1]);}
struct kdtree{
	int root,ans;
	point P;
	point t[maxn<<1];
	void rz(int p){
		for(int i=0;i<2;i++){
			if(t[p].l)t[p].mn[i]=min(t[p].mn[i],t[t[p].l].mn[i]),
			t[p].mx[i]=max(t[p].mx[i],t[t[p].l].mx[i]);
			if(t[p].r)t[p].mn[i]=min(t[p].mn[i],t[t[p].r].mn[i]),
			t[p].mx[i]=max(t[p].mx[i],t[t[p].r].mx[i]);
		}
	}
	int build(int l,int r,int dd){
		D=dd;int mid=(l+r)>>1;
		nth_element(p+l,p+mid,p+r+1);
		t[mid]=p[mid];
		for(int i=0;i<2;i++)t[mid].mn[i]=t[mid].mx[i]=t[mid][i];
		if(l<mid)t[mid].l=build(l,mid-1,dd^1);
		if(r>mid)t[mid].r=build(mid+1,r,dd^1);
		rz(mid);
		return mid;
	}
	void insert(int p,int dd){	
		
		if(P[dd]>=t[p][dd]){
			if(t[p].r)insert(t[p].r,dd^1);
			else{
				t[p].r=++n;
				t[n]=P;
				for(int i=0;i<2;i++)t[n].mn[i]=t[n].mx[i]=t[n][i];				
			}
		}else{
			if(t[p].l)insert(t[p].l,dd^1);
			else{
				t[p].l=++n;
				t[n]=P;
				for(int i=0;i<2;i++)t[n].mn[i]=t[n].mx[i]=t[n][i];				
			}			
		}rz(p);
	}
	int dist(int p1,point p){
	   int ans=0;
	   for(int i=0;i<2;i++)
	   ans+=max(0,t[p1].mn[i]-p[i]);
	   for(int i=0;i<2;i++)
	   ans+=max(0,p[i]-t[p1].mx[i]);
	   return ans;
	}
	void QkNN(int p,int dd){
	   int dl,dr,d0;
	   d0=dis(t[p],P);
	   if(d0<ans)ans=d0;
	   if(t[p].l)dl=dist(t[p].l,P);else dl=0x7f7f7f7f;
	   if(t[p].r)dr=dist(t[p].r,P);else dr=0x7f7f7f7f;
	   if(dl<dr){
	       if(dl<ans)QkNN(t[p].l,dd^1);
	       if(dr<ans)QkNN(t[p].r,dd^1);
	   }else{
	       if(dr<ans)QkNN(t[p].r,dd^1);
	       if(dl<ans)QkNN(t[p].l,dd^1);
	   }		
	}
	void insert(point _p){P=_p;insert(root,0);}
	void init(){root=build(1,n,0);}
	int QkNN(point _p){P=_p;ans=INT_MAX;QkNN(root,0);return ans;}
}T;
int main(){
	n=getint();m=getint();
	for(int i=1;i<=n;i++)p[i][0]=getint(),p[i][1]=getint();
	T.init();
	while(m--){
		int op=getint(),x=getint(),y=getint();
		if(op==1)T.insert(point(x,y));
		else printf("%d\n",T.QkNN(point(x,y)));
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值