bzoj4520: [Cqoi2016]K远点对

KD-tree裸题切切,人生有什么希望

找最远点对只要记录最大值,同样,找k远点对只要维护当前前k大值,每次和第k大比较即可。

//听说加const会变快?@lych_cys

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#define ll long long
#define N 100005
#define inf 1000000000
using namespace std;
int n,k,Rt,Q[2],D;
struct KD_node{int d[2],Mx[2],Mn[2],ls,rs;}T[N];
priority_queue<ll,vector<ll>,greater<ll> >q;
void Max(int &x,const int &y){if(x<y)x=y;}
void Min(int &x,const int &y){if(x>y)x=y;}
ll sqr(const int &x){return (ll)x*x;}
bool cmp(const KD_node &x,const KD_node &y){return x.d[D]<y.d[D];}
void update(int k)
{
	int l=T[k].ls,r=T[k].rs;
	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;k=mid;
	nth_element(T+l,T+mid,T+r+1,cmp);
	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);
}
ll ask(int k)
{
	if (!k) return 0;
	return max(sqr(T[k].Mn[0]-Q[0]),sqr(T[k].Mx[0]-Q[0]))+
		   max(sqr(T[k].Mn[1]-Q[1]),sqr(T[k].Mx[1]-Q[1]));
}
void qry(int k)
{
	ll dis=sqr(T[k].d[0]-Q[0])+sqr(T[k].d[1]-Q[1]);
	if (dis>q.top()) q.pop(),q.push(dis);
	ll Dl=ask(T[k].ls),Dr=ask(T[k].rs);
	if (Dl>Dr)
	{
		if (Dl>q.top()) qry(T[k].ls);
		if (Dr>q.top()) qry(T[k].rs);
	}
	else
	{
		if (Dr>q.top()) qry(T[k].rs);
		if (Dl>q.top()) qry(T[k].ls);
	}
}
int main()
{
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;i++)
		scanf("%d%d",&T[i].d[0],&T[i].d[1]);
	build(Rt,1,n,0);
	for (int i=1;i<=2*k;i++)q.push(0);
	for (int i=1;i<=n;i++)
		Q[0]=T[i].d[0],Q[1]=T[i].d[1],qry(Rt);
	printf("%lld\n",q.top());
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值