题解:P2093 [国家集训队] JZPFAR

更差的阅读体验


今天,我,学会了,K-D Tree。

简单讲一下这个数据结构的流程:我们把平面上的点按照某个维度上过某个点的一条分割线切开,以分割线穿过的这个点为根,递归处理左右两个子树。这样静态建出的树高度是 \(O(\log n)\) 当然是理想的,但是插入的时候会影响平衡性。所以可以用一些替罪羊的技巧,每插入若干个点重构一次,即可保证复杂度正确。

这个东西能做什么?可以在 \(O(n ^ \frac{1}{2})\) 的时间内做平面上的点对查询。

然后你就会发现这个题目就是 KDT 的模板。具体地,我们要在一个点中维护这个点所覆盖的矩形中最靠上、下、左、右的点。然后由于我们要求前 \(k\) 大,\(k\) 又非常小,我们可以用一个根堆来存前 \(k\) 大的点,其中堆顶是第 \(k\) 大。我们从根节点开始查询,先看看当前节点的这个点是不是当前的前 \(k\) 大,如果是,就把它插入到堆里面。接下来,我们可以求出左、右子树中的点到目标点的最大距离。如果左或右子树有可能成为前 \(k\) 大,就递归查询即可。

注意这里的最大距离是用我们之前维护的横、纵坐标的最大和最小值算出来的,因此会 \(\ge\) 实际上的最大距离,可以认为是被加入堆中的一个必要条件。

那么这道题就做完了,复杂度 \(O(n \sqrt n \log k)\)

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define N 100006
using namespace std;
int n,q,rt;
typedef pair<int,int> pii;
const double REVAL=0.75;
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline void chkmax(int &x,int y){x=x<y?y:x;}
int cmpx(int i,int j);
int cmpy(int i,int j);
struct KDT {
    int g[N],tot;
    struct Node {
        int val,sum,sz,ls,rs;
        int l,r,u,d,x,y,dir;
        Node(){val=sum=sz=ls=rs=l=r=u=d=x=y=dir=0;}
    }tree[N];
    priority_queue<pii,vector<pii>,greater<pii> > q;
    void push_up(int p)
    {
        int ls=tree[p].ls,rs=tree[p].rs;
        tree[p].sum=tree[ls].sum+tree[rs].sum+tree[p].val;
        tree[p].sz=tree[ls].sz+tree[rs].sz+1;
        tree[p].l=tree[p].r=tree[p].x,tree[p].u=tree[p].d=tree[p].y;
        if(ls)
        {
            chkmin(tree[p].l,tree[ls].l),chkmax(tree[p].r,tree[ls].r);
            chkmin(tree[p].d,tree[ls].d),chkmax(tree[p].u,tree[ls].u);
        } if(rs) {
            chkmin(tree[p].l,tree[rs].l),chkmax(tree[p].r,tree[rs].r);
            chkmin(tree[p].d,tree[rs].d),chkmax(tree[p].u,tree[rs].u);
        }
    }
    int build(int l,int r)
    {
        if(l>r)return 0;
        int mid=l+r>>1;
        double av1=0,av2=0,s1=0,s2=0;
        for(int i=l;i<=r;i++)av1+=tree[g[i]].x,av2+=tree[g[i]].y;
        av1/=r-l+1,av2/=r-l+1;
        for(int i=l;i<=r;i++)
            s1+=(tree[g[i]].x-av1)*(tree[g[i]].x-av1);
        for(int i=l;i<=r;i++)
            s2+=(tree[g[i]].y-av2)*(tree[g[i]].y-av2);
        if(s1>s2)nth_element(g+l,g+mid,g+r+1,cmpx),tree[g[mid]].dir=1;
        else nth_element(g+l,g+mid,g+r+1,cmpy),tree[g[mid]].dir=2;
        tree[g[mid]].ls=build(l,mid-1);
        tree[g[mid]].rs=build(mid+1,r);
        return push_up(g[mid]),g[mid];
    }
    void getord(int p)
    {
        if(!p)return;
        getord(tree[p].ls),g[++tot]=p,getord(tree[p].rs);
    }
    void rebuild(int &p){tot=0,getord(p),p=build(1,tot);}
    void insert(int &p,int v)
    {
        if(!p)return p=v,push_up(p),(void)0;
        if(tree[p].dir==1)
        {
            if(tree[v].x<=tree[p].x)insert(tree[p].ls,v);
            else insert(tree[p].rs,v);
        } else {
            if(tree[v].y<=tree[p].y)insert(tree[p].ls,v);
            else insert(tree[p].rs,v);
        }
        push_up(p);
        int ls=tree[p].ls,rs=tree[p].rs;
        if(tree[p].sz*REVAL<1.0*max(tree[ls].sz,tree[rs].sz))rebuild(p);
    }
	int get_dis(int x1,int y1,int x2,int y2)
	{
		int ret=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
		return ret;
	}
	int get_dis(int p,int x,int y)
	{
		int dx=max(abs(x-tree[p].l),abs(x-tree[p].r));
		int dy=max(abs(y-tree[p].u),abs(y-tree[p].d));
		return dx*dx+dy*dy;
	}
    void query(int p,int x,int y)
    {
        if(!p)return;
        pii cur=make_pair(get_dis(x,y,tree[p].x,tree[p].y),-p);
        if(cur>q.top())q.pop(),q.push(cur);
        int lmax=-1e15,rmax=-1e15,ls=tree[p].ls,rs=tree[p].rs;
        if(ls)lmax=get_dis(ls,x,y);
        if(rs)rmax=get_dis(rs,x,y);
        if(lmax<rmax)swap(lmax,rmax),swap(ls,rs);
        if(lmax>q.top().first)query(ls,x,y);
        if(rmax>q.top().first)query(rs,x,y);
    }
}T;
int cmpx(int i,int j){return T.tree[i].x<T.tree[j].x;}
int cmpy(int i,int j){return T.tree[i].y<T.tree[j].y;}
main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld%lld",&T.tree[i].x,&T.tree[i].y),T.insert(rt,i);
	scanf("%lld",&q);
	while(q--)
	{
		int x,y,k;scanf("%lld%lld%lld",&x,&y,&k);
		while(T.q.size())T.q.pop();
		for(int i=1;i<=k;i++)T.q.push(make_pair(-1e15,1));
		T.query(rt,x,y),printf("%lld\n",-T.q.top().second);
	}
	return 0;
}
posted @ 2025-09-18 16:35  dyc2022  阅读(9)  评论(0)    收藏  举报
/* 设置动态特效 */ /* 设置文章评论功能 */ 返回顶端 levels of contents