luogu P4357 [CQOI2016]K 远点对
题面传送门
KDT还可以做领域查询!只不过复杂度可以卡到单次\(O(n)\)
我们开一个小根堆维护答案,之后将每次答案与堆顶比较。如果答案比堆顶小就加入答案。
我们建立一颗KDT,然后每次计算每个点和当前矩形四个边框中最大的距离,如果这个距离大于当前堆顶,那么直接返回。否则继续递归下去。
但是这样并不最优,我们设立估价函数\(g(x)\)为目标点到\(x\)这个矩形内的最大距离,每次KDT走向儿子的过程中如果我们发现两个儿子都可以走,那么我们就挑选比较大的儿子先走,比较小的儿子后走,这样更容易走到正确答案。
综合上述优化我们的KDT就跑得飞快了尽管复杂度仍然是\(O(玄学)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M (1<<8)
#define K (6)
#define mod 12345678
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,k,Rt,cnt;priority_queue<ll,vector<ll>,greater<ll> > Q;struct Node{int x,y;}S[N];
namespace KDT{
I bool C1(Node x,Node y){return x.x<y.x;}I bool C2(Node x,Node y){return x.y<y.y;}int L[N],R[N],U[N],D[N],lc[N],rc[N];
I void Up(int v){L[v]=R[v]=S[v].x;U[v]=D[v]=S[v].y;lc[v]&&(L[v]=min(L[v],L[lc[v]]),R[v]=max(R[v],R[lc[v]]),U[v]=min(U[v],U[lc[v]]),D[v]=max(D[v],D[lc[v]]));rc[v]&&(L[v]=min(L[v],L[rc[v]]),R[v]=max(R[v],R[rc[v]]),U[v]=min(U[v],U[rc[v]]),D[v]=max(D[v],D[rc[v]]));}
I int BD(int l,int r){if(l>r) return 0;int m=l+r>>1,i;db avx=0,avy=0,vax=0,vay=0;for(i=l;i<=r;i++) avx+=S[i].x,avy+=S[i].y;avx/=r-l+1;avy/=r-l+1;
for(i=l;i<=r;i++) vax+=(avx-S[i].x)*(avx-S[i].x),vay+=(avy-S[i].y)*(avy-S[i].y);nth_element(S+l,S+m,S+r+1,vax>=vay?C1:C2);lc[m]=BD(l,m-1);rc[m]=BD(m+1,r);return Up(m),m;
}
I ll dis(int a,int b){if(!b) return -1e18;return max(1ll*(S[a].x-L[b])*(S[a].x-L[b]),1ll*(S[a].x-R[b])*(S[a].x-R[b]))+max(1ll*(S[a].y-U[b])*(S[a].y-U[b]),1ll*(S[a].y-D[b])*(S[a].y-D[b]));}
I void Qry(int x,int v){if(dis(x,v)<=Q.top()) return;if(!v) return;ll D1=1ll*(S[v].x-S[x].x)*(S[v].x-S[x].x)+1ll*(S[v].y-S[x].y)*(S[v].y-S[x].y),D2=dis(x,lc[v]),D3=dis(x,rc[v]);/*cnt++;*/D1>Q.top()&&(Q.pop(),Q.push(D1),0);D2>D3?(Qry(x,lc[v]),Qry(x,rc[v])):(Qry(x,rc[v]),Qry(x,lc[v]));}
}
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d%d",&n,&k);k*=2;for(i=1;i<=k;i++) Q.push(0);for(i=1;i<=n;i++) scanf("%d%d",&S[i].x,&S[i].y);Rt=KDT::BD(1,n);
for(i=1;i<=n;i++) KDT::Qry(i,Rt);printf("%lld\n",Q.top());//cerr<<cnt<<'\n';
}