刚学kd-tree,具体的操作网上都有,我就不赘述了。今天暂时只刷了一些曼哈顿距离的题目……都水水的,核心思想是记录出每个超平面(这个词好喜感=v=)的边缘坐标,利用估价函数判断询问点到两边超平面最近的距离是什么,然后先去那个超平面搜索,以达到启发式搜索和剪枝的目的。
具体来说,若要询问绿色的点,它到左边超平面最近的距离就是绿线的距离,我们就把这个距离作为估价函数就好了。(到右边的我没有画出来,但是估价函数会计算出0)
BZOJ2716 & 2648
双倍经验题+模板题,都是裸的询问离某个点曼哈顿距离最近的点是哪个点,直接用我上面说的算法就好了,询问的时候启发式搜索。
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 500000+5
#define INF 0x3f3f3f3f
using namespace std;
int n,m,dim,ans,root,cnt;
struct Point{
int x[2];
Point(int a=0,int b=0){ x[0]=a; x[1]=b; }
inline int& operator [](int i){ return x[i]; }
inline bool operator <(const Point &T)const{ return x[dim]<T.x[dim]; }
}p[maxn];
struct KD_Tree{
int l,r;
int mx[2],mi[2]; //记录边界,使用估价函数剪枝,需要维护一个子树的平面空间范围
Point t;
}tr[maxn<<1];
#define mid ((l+r)>>1)
inline int in(){
int x=0,f=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
for(; isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
inline void Update_mx(int &x,int y){ if(y>x) x=y; }
inline void Update_mi(int &x,int y){ if(y<x) x=y; }
inline int dis(Point a,Point b){
return abs(a[0]-b[0])+abs(a[1]-b[1]);
}
int calc(int k,Point x){
int res=0;
for(int i=0;i<2;i++){
res+=max(0,tr[k].mi[i]-x[i]);
res+=max(0,x[i]-tr[k].mx[i]);
}
return res;
}
void Update(int k){
for(int i=0;i<2;i++){
if(tr[k].l) Update_mx(tr[k].mx[i],tr[tr[k].l].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].l].mi[i]);
if(tr[k].r) Update_mx(tr[k].mx[i],tr[tr[k].r].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].r].mi[i]);
}
}
void Build(int &k,int l,int r,int d){
dim=d; k=++cnt;
nth_element(p+l,p+mid,p+r+1);
tr[k].t=p[mid];
for(int i=0;i<2;i++)
tr[k].mx[i]=tr[k].mi[i]=p[mid][i];
if(l<mid) Build(tr[k].l,l,mid-1,d^1);
if(mid<r) Build(tr[k].r,mid+1,r,d^1);
Update(k);
}
void Insert(int &k,Point pt,int d){
if(!k){
k=++cnt;
for(int i=0;i<2;i++) tr[k].mx[i]=tr[k].mi[i]=pt[i];
tr[k].t=pt; return;
}
dim=d;
if(pt<tr[k].t) Insert(tr[k].l,pt,d^1);
else Insert(tr[k].r,pt,d^1);
Update(k);
}
void Query(int k,Point pt,int d){
if(!k) return;
ans=min(ans,dis(pt,tr[k].t));
int lv=INF,rv=INF;
if(tr[k].l) lv=calc(tr[k].l,pt);
if(tr[k].r) rv=calc(tr[k].r,pt);
if(lv<rv){
if(lv<ans) Query(tr[k].l,pt,d^1);
if(rv<ans) Query(tr[k].r,pt,d^1);
}
else{
if(rv<ans) Query(tr[k].r,pt,d^1);
if(lv<ans) Query(tr[k].l,pt,d^1);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("2648.in","r",stdin);
freopen("2648.out","w",stdout);
#endif
n=in(); m=in();
for(int i=1;i<=n;i++){
p[i][0]=in(); p[i][1]=in();
}
Build(root,1,n,0);
for(int opt,x,y,i=1;i<=m;i++){
opt=in(); x=in(); y=in();
if(opt==1) Insert(root,Point(x,y),0);
else{
ans=INF;
Query(root,Point(x,y),0);
printf("%d\n",ans);
}
}
return 0;
}
BZOJ1941
跟上面一样是模板题……只需要枚举每个点进行询问,更新最近最远点之间的差就好了。
然而这题要还询问最远点,怎么办呢?
仿照最小值的估价函数也造一个差不多的就好了呗……意义是离某个超平面可能达到的最远距离。
(我会告诉你我偷懒从上面复制代码改了改吗?)
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 500000+5
#define INF 0x3f3f3f3f
using namespace std;
int n,m,dim,ans,ans1,ans2,root,cnt;
struct Point{
int x[2];
Point(int a=0,int b=0){ x[0]=a; x[1]=b; }
inline int& operator [](int i){ return x[i]; }
inline bool operator <(const Point &T)const{ return x[dim]<T.x[dim]; }
}p[maxn];
struct KD_Tree{
int l,r;
int mx[2],mi[2];
Point t;
}tr[maxn<<1];
#define mid ((l+r)>>1)
inline int in(){
int x=0,f=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
for(; isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
inline void Update_mx(int &x,int y){ if(y>x) x=y; }
inline void Update_mi(int &x,int y){ if(y<x) x=y; }
inline int dis(Point a,Point b){
return abs(a[0]-b[0])+abs(a[1]-b[1]);
}
int calc1(int k,Point x){
int res=0;
for(int i=0;i<2;i++){
res+=max(0,tr[k].mi[i]-x[i]);
res+=max(0,x[i]-tr[k].mx[i]);
}
return res;
}
int calc2(int k,Point x){
int res=0;
for(int i=0;i<2;i++)
res+=max(abs(x[i]-tr[k].mx[i]),abs(tr[k].mi[i]-x[i]));
return res;
}
void Update(int k){
for(int i=0;i<2;i++){
if(tr[k].l) Update_mx(tr[k].mx[i],tr[tr[k].l].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].l].mi[i]);
if(tr[k].r) Update_mx(tr[k].mx[i],tr[tr[k].r].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].r].mi[i]);
}
}
void Build(int &k,int l,int r,int d){
dim=d; k=++cnt;
nth_element(p+l,p+mid,p+r+1);
tr[k].t=p[mid];
for(int i=0;i<2;i++)
tr[k].mx[i]=tr[k].mi[i]=p[mid][i];
if(l<mid) Build(tr[k].l,l,mid-1,d^1);
if(mid<r) Build(tr[k].r,mid+1,r,d^1);
Update(k);
}
void Insert(int &k,Point pt,int d){
if(!k){
k=++cnt;
for(int i=0;i<2;i++) tr[k].mx[i]=tr[k].mi[i]=pt[i];
tr[k].t=pt; return;
}
dim=d;
if(pt<tr[k].t) Insert(tr[k].l,pt,d^1);
else Insert(tr[k].r,pt,d^1);
Update(k);
}
void Query_mi(int k,Point pt,int d){
if(!k) return;
if(dis(pt,tr[k].t)!=0) ans1=min(ans1,dis(pt,tr[k].t));
int lv=INF,rv=INF;
if(tr[k].l) lv=calc1(tr[k].l,pt);
if(tr[k].r) rv=calc1(tr[k].r,pt);
if(lv<rv){
if(lv<ans1) Query_mi(tr[k].l,pt,d^1);
if(rv<ans1) Query_mi(tr[k].r,pt,d^1);
}
else{
if(rv<ans1) Query_mi(tr[k].r,pt,d^1);
if(lv<ans1) Query_mi(tr[k].l,pt,d^1);
}
}
void Query_mx(int k,Point pt,int d){
if(!k) return;
ans2=max(ans2,dis(pt,tr[k].t));
int lv=-INF,rv=-INF;
if(tr[k].l) lv=calc2(tr[k].l,pt);
if(tr[k].r) rv=calc2(tr[k].r,pt);
if(lv>rv){
if(lv>ans2) Query_mx(tr[k].l,pt,d^1);
if(rv>ans2) Query_mx(tr[k].r,pt,d^1);
}
else{
if(rv>ans2) Query_mx(tr[k].r,pt,d^1);
if(lv>ans2) Query_mx(tr[k].l,pt,d^1);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1941.in","r",stdin);
freopen("1941.out","w",stdout);
#endif
n=in();
for(int i=1;i<=n;i++){
p[i][0]=in(); p[i][1]=in();
}
Build(root,1,n,0); ans=INF;
for(int i=1;i<=n;i++){
ans1=INF; ans2=-INF;
Query_mi(root,p[i],0); Query_mx(root,p[i],0);
ans=min(ans,ans2-ans1);
}
printf("%d",ans);
return 0;
}
刷了几天……感觉KD-Tree就是个暴力+优化= =
BZOJ4066
这个题有插入操作,插入太多次以后KD树没办法保持平衡……于是到一定的次数就重构一次树好了……
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 200000+5
using namespace std;
int dim,n,cnt,root,ans,pos;
struct Point{
int x[2],val;
Point(int a=0,int b=0,int c=0){ x[0]=a; x[1]=b; val=c; }
inline int operator [] (int i){ return x[i]; }
inline bool operator < (const Point &T)const{ return x[dim]<T.x[dim]; }
}p[maxn];
struct KD_Tree{
int l,r,sum;
int mx[2],mi[2];
Point t;
}tr[maxn];
inline int in(){
int x=0,f=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
for(; isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
inline void Update_mx(int &x,int y){ if(y>x) x=y; }
inline void Update_mi(int &x,int y){ if(y<x) x=y; }
void Update(int k){
for(int i=0;i<2;i++){
if(tr[k].l) Update_mx(tr[k].mx[i],tr[tr[k].l].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].l].mi[i]);
if(tr[k].r) Update_mx(tr[k].mx[i],tr[tr[k].r].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].r].mi[i]);
}
tr[k].sum=tr[tr[k].l].sum+tr[tr[k].r].sum+tr[k].t.val;
}
void Insert(int &k,Point pt,int d){
if(!k){
k=++cnt; tr[k].t=pt; tr[k].sum=pt.val;
for(int i=0;i<2;i++) tr[k].mx[i]=tr[k].mi[i]=pt[i];
return;
}
if(pt[0]==tr[k].t[0] && pt[1]==tr[k].t[1]){ tr[k].sum+=pt.val; tr[k].t.val+=pt.val; return; }
dim=d;
if(pt<tr[k].t) Insert(tr[k].l,pt,d^1);
else Insert(tr[k].r,pt,d^1);
Update(k);
}
inline bool cross(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4){
if(x1<x4 || x2>x3 || y2<y3 || y1>y4) return false;
return true;
}
inline bool cover(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4){ //1-2 cover 3-4
if(y1<=y3 && y2>=y4 && x1>=x3 && x2<=x4) return true;
return false;
}
int Query(int k,int x1,int y1,int x2,int y2){
if(cover(x1,y1,x2,y2,tr[k].mx[0],tr[k].mi[1],tr[k].mi[0],tr[k].mx[1])) return tr[k].sum;
int tmp=0,l=tr[k].l,r=tr[k].r;
if(tr[k].t[0]<=x1 && tr[k].t[0]>=x2 && tr[k].t[1]>=y1 && tr[k].t[1]<=y2) tmp+=tr[k].t.val;
if(l && cross(x1,y1,x2,y2,tr[l].mx[0],tr[l].mi[1],tr[l].mi[0],tr[l].mx[1])) tmp+=Query(l,x1,y1,x2,y2);
if(r && cross(x1,y1,x2,y2,tr[r].mx[0],tr[r].mi[1],tr[r].mi[0],tr[r].mx[1])) tmp+=Query(r,x1,y1,x2,y2);
return tmp;
}
#define mid ((l+r)>>1)
void Rebuild(int &k,int l,int r,int d){
dim=d; k=++cnt;
nth_element(p+l,p+mid,p+r+1);
tr[k].t=p[mid];
for(int i=0;i<2;i++) tr[k].mx[i]=tr[k].mi[i]=p[mid][i];
if(l<mid) Rebuild(tr[k].l,l,mid-1,d^1);
else tr[k].l=0;
if(r>mid) Rebuild(tr[k].r,mid+1,r,d^1);
else tr[k].r=0;
Update(k);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("4066.in","r",stdin);
freopen("4066.out","w",stdout);
#endif
n=in(); int flag=10000;
for(int opt;(opt=in())!=3;){
if(opt==1){
int x,y,c;
x=in()^ans; y=in()^ans; c=in()^ans;
Insert(root,Point(x,y,c),0);
if(cnt==flag){
for(int i=1;i<=cnt;i++) p[i]=tr[i].t,tr[i].sum=0;
int tmp=cnt; cnt=0; flag+=10000;
Rebuild(root,1,tmp,0);
}
}
else{
int x1,y1,x2,y2;
x1=in()^ans; y1=in()^ans; x2=in()^ans; y2=in()^ans;
printf("%d\n",ans=Query(root,x2,y1,x1,y2));
}
}
return 0;
}
BZOJ2850
计算一个矩形内的贡献和计算一个半平面的贡献都差不多……
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 50000+5
using namespace std;
typedef long long LL;
int n,m,dim,root,cnt;
struct Point{
int x[2],h;
Point(int a=0,int b=0,int c=0){ x[0]=a; x[1]=b; h=c; }
inline int operator [] (int i){ return x[i]; }
inline bool operator < (const Point &T)const{ return x[dim]<T.x[dim]; }
}p[maxn];
struct KD_Tree{
int l,r; LL sum;
int mx[2],mi[2];
Point t;
}tr[maxn];
inline int in(){
int x=0,f=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
for(; isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
#define mid ((l+r)>>1)
inline void Update_mx(int &x,int y){ if(y>x) x=y; }
inline void Update_mi(int &x,int y){ if(y<x) x=y; }
void Update(int k){
for(int i=0;i<2;i++){
if(tr[k].l) Update_mx(tr[k].mx[i],tr[tr[k].l].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].l].mi[i]);
if(tr[k].r) Update_mx(tr[k].mx[i],tr[tr[k].r].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].r].mi[i]);
}
tr[k].sum=tr[tr[k].l].sum+tr[tr[k].r].sum+tr[k].t.h;
}
void Build(int &k,int l,int r,int d){
if(l>r){ k=0; return; }
dim=d; k=++cnt;
nth_element(p+l,p+mid,p+r+1);
tr[k].t=p[mid];
for(int i=0;i<2;i++) tr[k].mi[i]=tr[k].mx[i]=p[mid][i];
Build(tr[k].l,l,mid-1,d^1);
Build(tr[k].r,mid+1,r,d^1);
Update(k);
}
inline bool cover(int x,int y,int a,int b,int c){
return a*x+b*y<c;
}
int calc(int k,int a,int b,int c){
int tmp=0;
tmp+=cover(tr[k].mx[0],tr[k].mx[1],a,b,c);
tmp+=cover(tr[k].mx[0],tr[k].mi[1],a,b,c);
tmp+=cover(tr[k].mi[0],tr[k].mx[1],a,b,c);
tmp+=cover(tr[k].mi[0],tr[k].mi[1],a,b,c);
return tmp;
}
LL Query(int k,int a,int b,int c){
if(calc(k,a,b,c)==4) return tr[k].sum;
LL tmp=0;
if(tr[k].l && calc(tr[k].l,a,b,c)) tmp+=Query(tr[k].l,a,b,c);
if(tr[k].r && calc(tr[k].r,a,b,c)) tmp+=Query(tr[k].r,a,b,c);
if(cover(tr[k].t[0],tr[k].t[1],a,b,c)) tmp+=tr[k].t.h;
return tmp;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("2850.in","r",stdin);
freopen("2850.out","w",stdout);
#endif
n=in(); m=in();
for(int i=1;i<=n;i++){
p[i].x[0]=in(); p[i].x[1]=in(); p[i].h=in();
}
Build(root,1,n,0);
for(int a,b,c,i=1;i<=m;i++){
a=in(); b=in(); c=in();
printf("%lld\n",Query(root,a,b,c));
}
return 0;
}
BZOJ4154
稍微分析一下,发现这个点的染色范围在dfs序的一个区间内,在深度的一个区间内,把这个看成横纵坐标就可以转化成一个矩形内的点的涂色了……直接KD-Tree+Tag下传
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define maxn 100000+5
#define mod 1000000007
using namespace std;
int n,c,q,dim,cnt,root,ans,ind,timer;
struct Point{
int x[2],col,id;
Point(int a=0,int b=0,int co=0,int d=0){ x[0]=a; x[1]=b; col=co; id=d; }
inline int operator [] (int i){ return x[i]; }
inline bool operator < (const Point &T)const{
if(x[dim]==T.x[dim]) return x[dim^1]<T.x[dim^1];
return x[dim]<T.x[dim];
}
}p[maxn];
struct KD_Tree{
int l,r,tag;
int mx[2],mi[2];
Point t;
}tr[maxn];
struct Edge{
int u,v,nxt;
}e[maxn<<1];
int head[maxn],dfn[maxn],last[maxn],dep[maxn],pos[maxn];
inline int in(){
int x=0,f=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
for(; isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
inline void addedge(int x,int y){
e[ind]=(Edge){x,y,head[x]},head[x]=ind++;
}
inline bool cmp(const Point &s,const Point &b){
return s.id<b.id;
}
void dfs(int x){
dfn[x]=++timer;
for(int i=head[x];i!=-1;i=e[i].nxt){
dep[e[i].v]=dep[x]+1;
dfs(e[i].v);
}
last[x]=timer;
}
#define mid ((l+r)>>1)
inline void Update_mx(int &x,int y){ if(x<y) x=y; }
inline void Update_mi(int &x,int y){ if(x>y) x=y; }
void Update(int k){
for(int i=0;i<2;i++){
if(tr[k].l) Update_mx(tr[k].mx[i],tr[tr[k].l].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].l].mi[i]);
if(tr[k].r) Update_mx(tr[k].mx[i],tr[tr[k].r].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].r].mi[i]);
}
}
void Build(int &k,int l,int r,int d){
if(l>r){ k=0; return; }
dim=d; k=++cnt;
nth_element(p+l,p+mid,p+r+1);
tr[k].t=p[mid]; tr[k].tag=-1; pos[p[mid].id]=k;
for(int i=0;i<2;i++) tr[k].mx[i]=tr[k].mi[i]=p[mid][i];
Build(tr[k].l,l,mid-1,d^1); Build(tr[k].r,mid+1,r,d^1);
Update(k);
}
#undef mid
void Pushdown(int k){
int l=tr[k].l,r=tr[k].r;
if(tr[k].tag!=-1){
if(l) tr[l].t.col=tr[l].tag=tr[k].tag;
if(r) tr[r].t.col=tr[r].tag=tr[k].tag;
tr[k].tag=-1;
}
}
inline bool cover(int a,int b,int c,int d,int x1,int y1,int x2,int y2){
return a<=x1 && c>=x2 && b>=y1 && d<=y2;
}
inline bool out(int a,int b,int c,int d,int x1,int y1,int x2,int y2){
return a<x2 || c>x1 || b>y2 || d<y1;
}
void Modify(int k,int x1,int y1,int x2,int y2,int co){
Pushdown(k);
if(cover(tr[k].mx[0],tr[k].mi[1],tr[k].mi[0],tr[k].mx[1],x1,y1,x2,y2)){
tr[k].t.col=co; tr[k].tag=co;
return;
}
int l=tr[k].l,r=tr[k].r;
if(cover(tr[k].t[0],tr[k].t[1],tr[k].t[0],tr[k].t[1],x1,y1,x2,y2)) tr[k].t.col=co;
if(l && !out(tr[l].mx[0],tr[l].mi[1],tr[l].mi[0],tr[l].mx[1],x1,y1,x2,y2)) Modify(l,x1,y1,x2,y2,co);
if(r && !out(tr[r].mx[0],tr[r].mi[1],tr[r].mi[0],tr[r].mx[1],x1,y1,x2,y2)) Modify(r,x1,y1,x2,y2,co);
}
int Query(int k,Point pt,int d){
Pushdown(k); dim=d;
if(pt[0]==tr[k].t[0] && pt[1]==tr[k].t[1]) return tr[k].t.col;
if(pt<tr[k].t) return Query(tr[k].l,pt,d^1);
else return Query(tr[k].r,pt,d^1);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("4154.in","r",stdin);
freopen("4154.out","w",stdout);
#endif
int T;
T=in();
while(T--){
n=in(); c=in(); q=in(); ind=timer=cnt=ans=0;
memset(head,-1,sizeof(head));
for(int fa,i=2;i<=n;i++){
fa=in(); addedge(fa,i);
}
dfs(1);
for(int i=1;i<=n;i++)
p[i]=Point(dfn[i],dep[i],1,i);
Build(root,1,n,0);
sort(p+1,p+1+n,cmp);
for(int tmp,a,l,col,i=1;i<=q;i++){
a=in(); l=in(); col=in();
if(col) Modify(root,last[a],dep[a],dfn[a],dep[a]+l,col);
else ans=(1ll*i*Query(root,p[a],0)+ans)%mod;
}
printf("%d\n",ans);
}
return 0;
}
BZOJ4520
这题跟之前题的套路差不多,枚举每个点进行查询,搞个优先队列记录一下前K个点就好了。因为这题会有重复,记录前2k个就避免算重了。
#include<queue>
#include<cstdio>
#include<cctype>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define maxn 100000+5
#define INF (LLONG_MAX-233)
using namespace std;
typedef long long LL;
int n,dim,cnt,root,K;
LL ans;
struct Point{
int x[2];
inline int operator [] (int i){ return x[i]; }
inline bool operator < (const Point &T)const{
if(x[dim]==T.x[dim]) return x[dim^1]<T.x[dim^1];
return x[dim]<T.x[dim];
}
}p[maxn];
struct KD_Tree{
int l,r;
int mi[2],mx[2];
Point t;
}tr[maxn];
priority_queue <LL,vector<LL>,greater<LL> > q;
inline int in(){
int x=0; char ch=getchar();
for(;!isdigit(ch);ch=getchar());
for(; isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
inline void Update_mx(int &x,int y){ if(y>x) x=y; }
inline void Update_mi(int &x,int y){ if(y<x) x=y; }
inline LL sqr(LL x){ return x*x; }
void Update(int k){
for(int i=0;i<2;i++){
if(tr[k].l) Update_mx(tr[k].mx[i],tr[tr[k].l].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].l].mi[i]);
if(tr[k].r) Update_mx(tr[k].mx[i],tr[tr[k].r].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].r].mi[i]);
}
}
#define mid ((l+r)>>1)
void Build(int &k,int l,int r,int d){
if(l>r){ k=0; return; }
dim=d; k=++cnt;
nth_element(p+l,p+mid,p+r+1);
tr[k].t=p[mid];
for(int i=0;i<2;i++) tr[k].mi[i]=tr[k].mx[i]=p[mid][i];
Build(tr[k].l,l,mid-1,d^1); Build(tr[k].r,mid+1,r,d^1);
Update(k);
}
LL calc(int k,Point pt){
LL res=0;
for(int i=0;i<2;i++)
res+=max(sqr(pt[i]-tr[k].mx[i]),sqr(pt[i]-tr[k].mi[i]));
return res;
}
LL dis(Point a,Point b){
return sqr(a[0]-b[0])+sqr(a[1]-b[1]);
}
void Query(int k,Point pt){
LL tmp1=0,tmp2=0,tmp3=0;
tmp1=dis(tr[k].t,pt);
if(q.top()<tmp1) q.pop(),q.push(tmp1);
if(tr[k].l) tmp2=calc(tr[k].l,pt);
if(tr[k].r) tmp3=calc(tr[k].r,pt);
if(tmp2>tmp3){
if(tr[k].l && q.top()<tmp2) Query(tr[k].l,pt);
if(tr[k].r && q.top()<tmp3) Query(tr[k].r,pt);
}
else{
if(tr[k].r && q.top()<tmp3) Query(tr[k].r,pt);
if(tr[k].l && q.top()<tmp2) Query(tr[k].l,pt);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("4520.in","r",stdin);
freopen("4520.out","w",stdout);
#endif
n=in(); K=in()*2;
for(int i=1;i<=K;i++) q.push(0);
for(int i=1;i<=n;i++){
p[i].x[0]=in(); p[i].x[1]=in();
}
Build(root,1,n,0);
for(int i=1;i<=n;i++)
Query(root,p[i]);
printf("%lld",q.top());
return 0;
}