LuoguP2093/Bzoj2626. JZPFAR

题面:

https://www.luogu.org/problemnew/show/P2093

https://darkbzoj.cf/problem/2626

思路:

算是kd-tree裸题,对于查询的数维护含k个数的小根堆,这个堆中装的是距离最大的k个数

WA了挺久,有一些情况要注意

1.堆中存放的要是一个结构体,bh为编号,val为距离,只能定义 ' < ',且默认大根堆,我们不妨反过来定义,详情见程序

2.p[i]虽然一开始是有序的,但建树的时候就把顺序打乱了,不能轻易认为p[i]中的i就是第i个节点,要再保存一个p[i].bh记录的才是编号

3.本来query中是否向儿子管辖区域找我写的是val>=即可,结果TLE,所以要优化一下,顶一个数组mbh[i],存管辖范围内最小编号,用法参照mn[i],mx[i]

#include<bits/stdc++.h>
#define lc (ch[x][0])
#define rc (ch[x][1])
#define ll long long
using namespace std;
const int maxn=1e6+4;
int n,m;
ll mn[maxn][2],mx[maxn][2],ch[maxn][2],mbh[maxn];
int nthdir;
struct node{
    int bh;ll val;
    bool operator < (const node &no) const{
        if(no.val==val) return bh<no.bh;
        return val>no.val;
    }
    node(int x,long long y){
        bh=x;val=y;
    }
};
priority_queue<node>q;
inline ll sq(ll x){
    return (ll)x*x;
}
struct Point{
    ll pos[2];int bh;
    ll& operator [](int x){
        return pos[x];
    }
    bool operator < (const Point &t) const {
        return pos[nthdir] < t.pos[nthdir];
    }
    ll operator - (const Point &t) const {
        return (ll)sq(pos[0]-t.pos[0])+(ll)sq(pos[1]-t.pos[1]);
    }
    Point(ll x,ll y,int b){
        pos[0]=x;pos[1]=y;bh=b;
    }
    Point(){};
}p[maxn];
inline void pushup(int x){
    for(int i=0;i<=1;i++){
        mn[x][i]=mx[x][i]=p[x][i];
        mbh[x]=p[x].bh;
        if(lc){
            mn[x][i]=min(mn[x][i],mn[lc][i]);
            mx[x][i]=max(mx[x][i],mx[lc][i]);
            mbh[x]=min(mbh[x],mbh[lc]);
        }
        if(rc){
            mn[x][i]=min(mn[x][i],mn[rc][i]);
            mx[x][i]=max(mx[x][i],mx[rc][i]);
            mbh[x]=min(mbh[x],mbh[rc]);
        }
    }
}
inline int build(int l,int r,int dir){
    nthdir=dir;
    int x=(l+r)>>1;
    nth_element(p+l,p+x,p+r+1);
    if(l<x) lc=build(l,x-1,dir^1);
    if(r>x) rc=build(x+1,r,dir^1);
    pushup(x);return x;
}
inline ll calc(int x,Point P){
    return max((ll)sq(mn[x][0]-P[0]),(ll)sq(mx[x][0]-P[0]))+max((ll)sq(mn[x][1]-P[1]),(ll)sq(mx[x][1]-P[1]));
}
inline void query(int x,Point P){
    ll h=P-p[x];
    if(node(p[x].bh,h) < q.top()){
        q.pop();
        q.push(node(p[x].bh,h));
    }
    ll l=-(maxn<<1),r=-(maxn<<1);
    if(lc) l=calc(lc,P);
    if(rc) r=calc(rc,P);
    if(l>r){
        if(node(mbh[lc],l)<q.top()) query(lc,P);
        if(node(mbh[rc],r)<q.top()) query(rc,P);
        //上面和下面这两组语句等价 
        //if(q.top().val<l||(q.top().val==l&&q.top().bh>mbh[lc])) query(lc,P);
        //if(q.top().val<r||(q.top().val==r&&q.top().bh>mbh[rc])) query(rc,P);
    }else{
        if(node(mbh[rc],r)<q.top()) query(rc,P);
        if(node(mbh[lc],l)<q.top()) query(lc,P);
        //if(q.top().val<r||(q.top().val==r&&q.top().bh>mbh[rc])) query(rc,P);
        //if(q.top().val<l||(q.top().val==l&&q.top().bh>mbh[lc])) query(lc,P);
    }
}
int main(){
    memset(mn,0x3f,sizeof(mn));
    memset(mx,0xc0,sizeof(mx));
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld%lld",&p[i][0],&p[i][1]),p[i].bh=i;
    int rt=build(1,n,0);
    scanf("%d",&m);
    while(m--){
        int x,y,k;scanf("%lld%lld%d",&x,&y,&k);
        while(!q.empty()) q.pop();
        for(int i=1;i<=k;i++) q.push(node(0,-maxn));
        query(rt,Point(x,y,0));
        printf("%d\n",(q.top()).bh);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wifimonster/p/10514221.html