K-D Tree

130 篇文章 1 订阅
92 篇文章 0 订阅

就是用一些的方法把平面按点分成若干块,

方便你剪枝(这思路真暴力)

因为是剪枝暴力,复杂度是O(能过),可以拿来干超级多的事情

CQOI2016 :  K远点对


#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<queue>
#include<functional>
#define LL long long
#define maxn 100005
#define inf 0x3f3f3f3f
using namespace std;

int D,root,n,k;
struct Point
{
	int d[2];
	bool operator <(const Point &Ano)const{ return d[D]<Ano.d[D]; }
}P[maxn];

struct Area
{
	int d[2],x[2],y[2],son[2];
}tr[maxn];

void upd(int now,int pre)
{
	tr[now].x[0]=min(tr[now].x[0],tr[pre].x[0]);
	tr[now].x[1]=max(tr[now].x[1],tr[pre].x[1]);
	tr[now].y[0]=min(tr[now].y[0],tr[pre].y[0]);
	tr[now].y[1]=max(tr[now].y[1],tr[pre].y[1]);
}

int build(int L,int R,int dir)
{
	D=dir;int mid=(L+R)>>1;
	nth_element(P+L,P+mid,P+1+R);
	tr[mid].d[0]=tr[mid].x[0]=tr[mid].x[1]=P[mid].d[0];
	tr[mid].d[1]=tr[mid].y[0]=tr[mid].y[1]=P[mid].d[1];
	if(L<mid) tr[mid].son[0]=build(L,mid-1,dir^1),upd(mid,tr[mid].son[0]);
	if(R>mid) tr[mid].son[1]=build(mid+1,R,dir^1),upd(mid,tr[mid].son[1]);
	return mid;
}

inline LL sqr(int a)
{
	return 1ll*a*a;
}

inline LL getdist(int now,int x,int y)
{
	return max(sqr(x-tr[now].x[0]),sqr(x-tr[now].x[1]))+max(sqr(y-tr[now].y[0]),sqr(y-tr[now].y[1]));
}

priority_queue<LL,vector<LL>,greater<LL> >Q;
void Query(int now,int x,int y)
{
	LL dist=sqr(x-tr[now].d[0])+sqr(y-tr[now].d[1]),dis[2];
	Q.push(dist);
	while(Q.size()>k) Q.pop();
	dis[0]=tr[now].son[0] ? getdist(tr[now].son[0],x,y) : -inf;
	dis[1]=tr[now].son[1] ? getdist(tr[now].son[1],x,y) : -inf;
	dist=dis[0]<dis[1];
	if(dis[dist]>=Q.top() || Q.size()<k)   Query(tr[now].son[dist],x,y);
	if(dis[dist^1]>=Q.top() || Q.size()<k) Query(tr[now].son[dist^1],x,y);
}

char ch;bool flag;
inline void get(int &res)
{
	for(flag=0;!isdigit(ch=getchar());) if(ch=='-') flag=1;
	for(res=ch-'0';isdigit(ch=getchar());res=res*10+ch-'0');
	(flag) && (res=-res);
}

int main()
{
	get(n),get(k);k*=2;
	for(int i=1;i<=n;i++) get(P[i].d[0]),get(P[i].d[1]);
	root=build(1,n,0);
	for(int i=1;i<=n;i++)
		Query(root,tr[i].d[0],tr[i].d[1]);
	printf("%lld\n",Q.top());
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值