luogu P2093 [国家集训队]JZPFAR (k-d tree难一点点的模板题)

人生中第一个洛谷黑题,献给了k-d tree。

题目链接:https://www.luogu.com.cn/problem/P2093

题意:最开始给定n个点(n<=1e5)。然后给定m个询问(m<=1e4),包含xi,yi,k。(每次询问输出距离(xi,yi)第k远的点。注意,如果距离相同,那么索引小的算距离大的)。

题解:最近连k-d tree。专门找的这种类型的题目,再点开标签,只有k-d tree那么用它无疑了。

之前学过的k-d tree的操作:build,query,rebuild,maintain,insert。

这题显然需要先用build(同时maintain),然后再query就欧克了。

之前也做过查询所有点对中第k大的数,现在改成离某个点第k大的点就ok了。

首先build操作用差分优化一下树,用maintain存储都是常规操作。

本来query也是常规操作,但是,emmm我走远了(可能是前两天练过的还是不熟练把,需要比q.top大的点,那么判断点(xi,yi)到矩阵中最远的距离是否大于等于q.top就好了。再在边界的时候判断一下待插入点与q.top的距离就好了)。

还有注意,结构体的顺序会在build的时候改变。。。

emmmm写的很粗略,我认为我自己都看不太懂emmmm.唉本来也只是打算记录一下自己的心情。

记住:::
k-d tree的操作都挺模板的,我们需要关注的是不一样的地方!!!思路要清晰,不要“走远了”

代码:

#include 

#define ll long long
#define ld double
#define pi acos(-1)
#define pb push_back
#define mst(a, i) memset(a, i, sizeof(a))
#define pll pair
#define fi first
#define se second
#define mp(x,y) make_pair(x,y)
#define Max(a,b) (a<=b?b:a)
#define Min(a,b) (a>=b?b:a)
#define Abs(x) (x>=0?x:-1*(x))
#define rep(i,a,n)  for(ll i=a;i<=n;i++)
#define per(i,n,a)  for(ll i=n;i>=a;i--)
#define dbg(x) cout << #x << "===" << x << endl
#define dbgg(l,r,x) for(ll i=l;i<=r;i++) cout<'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();return s*w;}
//templatevoid read(T &x){T res=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){res=(res<<3)+(res<<1)+c-'0';c=getchar();}x=res*f;}
inline void print(ll x){if(x<0){putchar('-');x=-x;}if(x>9)print(x/10);putchar(x%10+'0');}
const ll maxn = 1e5 + 10;
const ll mod = 1e9 + 7;

ll n,m,k,xi,yi;
struct node{
    ll id,x,y;/*
    bool operator > (const node &a) const{
        if(Abs(xi-x)+Abs(yi-y)==Abs(xi-a.x)+Abs(yi-a.y)) return id>a.id;
        else 
        return Abs(xi-x)+Abs(yi-y)>Abs(xi-a.x)+Abs(yi-a.y);
    }*/
}s[maxn];
ll cur,d[maxn],L[maxn],R[maxn],U[maxn],D[maxn],lc[maxn],rc[maxn];
bool cmp1(node a,node b){return a.xpw(xi-s[b].x)+pw(yi-s[b].y);
    }
};
priority_queue,cmp > q;
void maintain(ll x){
    L[x]=R[x]=s[x].x;
    D[x]=U[x]=s[x].y;
    if(lc[x]){
        L[x]=Min(L[x],L[lc[x]]),R[x]=Max(R[x],R[lc[x]]);
        D[x]=Min(D[x],D[lc[x]]),U[x]=Max(U[x],U[lc[x]]);
    }
    if(rc[x]){
        L[x]=Min(L[x],L[rc[x]]),R[x]=Max(R[x],R[rc[x]]);
        D[x]=Min(D[x],D[rc[x]]),U[x]=Max(U[x],U[rc[x]]);
    }
}
ll build(ll l,ll r){
    if(l>r) return 0;
    ll mid=(l+r)>>1;
    ld x0=0,y0=0,x1=0,y1=0;
    rep(i,l,r) x0+=s[i].x,y0+=s[i].y;
    x0/=(ld)(r-l+1),y0/=(ld)(r-l+1);
    rep(i,l,r) x1+=pw(x0-s[i].x),y1+=pw(y0-s[i].y);
    if(x1>y1) d[mid]=1,nth_element(s+l,s+mid,s+r+1,cmp1);
    else d[mid]=2,nth_element(s+l,s+mid,s+r+1,cmp2);
    lc[mid]=build(l,mid-1);
    rc[mid]=build(mid+1,r);
    maintain(mid);
    return mid;
}
ll f(ll x){
    return Max(pw(L[x]-xi),pw(R[x]-xi))+Max(pw(D[x]-yi),pw(U[x]-yi));
}
bool ok(ll a,ll b){
    if(pw(xi-s[a].x)+pw(yi-s[a].y)==pw(xi-s[b].x)+pw(yi-s[b].y)) return s[a].idpw(xi-s[b].x)+pw(yi-s[b].y);
}
#define qx q.top()
#define dis (pw(xi-s[qx].x)+pw(yi-s[qx].y))

void query(ll l,ll r){
    if(l>r) return ;
    ll mid=(l+r)>>1;//,t=dis(mid);
    if(ok(mid,qx)) q.pop(),q.push(mid);
    ll dl=f(lc[mid]),dr=f(rc[mid]);
    if(dl>=dis&&dr>=dis){
        if(dl>dr){
            query(l,mid-1);
            if(dr>=dis) query(mid+1,r);
        } 
        else{
            query(mid+1,r);
            if(dl>=dis) query(l,mid-1);
        }
    }
    else{
        if(dl>=dis) query(l,mid-1);
        if(dr>=dis) query(mid+1,r);
    }
}
//ll inv(ll a){return a==1?1:(ll)(mod-mod/a)*inv(mod%a)%mod;}
//ll gcd(ll a,ll b){return (b==0)?a:gcd(b,a%b);}
//ll qpow(ll a,ll p,ll mod){ll ans=1;a=a%mod;while(p){if(p&1)ans=(ans*a)%mod;p>>=1;a=(a*a)%mod;}return ans;}
int main() {
    ll _s = 1;
    //_s=read();
    for (ll _=1;_<=_s;_++) {
        n=read();
        rep(i,1,n) s[i].x=read(),s[i].y=read(),s[i].id=i;
        build(1,n);
        m=read();
        while(m--){
            xi=read(),yi=read(),k=read();
            s[0].id=1e8,s[0].x=xi,s[0].y=yi;//{1e18,xi,yi};
            while(!q.empty()) q.pop();
            rep(i,1,k) q.push(0);//?不用乘双倍,因为就一个点到其他的点
            query(1,n);
            //cout<<"<<<<<<<<<<<<<<<";
            ll ans=s[qx].id;
            print(ans),putchar('\n');


            //rep(i,1,n) cout<>>"<

 

你可能感兴趣的:(#,ACM_数据结构)