题面:
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 ",(q.top()).bh); } return 0; }