kd-tree题目总结

在竞赛中,kd-tree一般只用于平面,很少有高于二维的情况。

在随机情况下,kd-tree的复杂度为O(NlogN),但会被极端数据卡到平方级别。

总而言之,就是优美的暴力。

查询时,通过估价函数进行减值。当然,这个函数一定要大于等于最后的结果,才有正确性。

1.求平面最近点对,欧几里得距离。精确到小数点后4位。

模板,不解释。

 1 // luogu-judger-enable-o2
 2 // luogu-judger-enable-o2
 3 #include<bits/stdc++.h>
 4 using namespace std;
 5 const double eps=0.00001;
 6 const double inf=1E18; 
 7 const int maxn=2E5+5;
 8 int n,m;
 9 int son[maxn][2],size;
10 double val[maxn][2],minv[maxn][2],maxv[maxn][2],ans,v[2];
11 struct pt{double v[2];}a[maxn];
12 bool cmp0(pt x,pt y){return x.v[0]<y.v[0];}
13 bool cmp1(pt x,pt y){return x.v[1]<y.v[1];}
14 bool cmp2(pt x,pt y)
15 {
16     if(x.v[0]==y.v[0])return x.v[1]<y.v[1];
17     return x.v[0]<y.v[0];
18 }
19 inline void update(int x,int y)
20 {
21     for(int i=0;i<2;++i)
22     {
23         minv[x][i]=min(minv[x][i],minv[y][i]);
24         maxv[x][i]=max(maxv[x][i],maxv[y][i]);
25     }
26 }
27 void build(int l,int r,int dep,int num)
28 {
29     int mid=(l+r)>>1;
30     if(dep%2==1)nth_element(a+l,a+mid,a+r+1,cmp0);
31     else nth_element(a+l,a+mid,a+r+1,cmp1);
32     minv[num][0]=maxv[num][0]=val[num][0]=a[mid].v[0];
33     minv[num][1]=maxv[num][1]=val[num][1]=a[mid].v[1];
34     if(l<=mid-1)
35     {
36         build(l,mid-1,dep+1,son[num][0]=++size);
37         update(num,son[num][0]);
38     }
39     if(mid+1<=r)
40     {
41         build(mid+1,r,dep+1,son[num][1]=++size);
42         update(num,son[num][1]);
43     }
44 }
45 inline double s(double x){return x*x;}
46 inline double dis(int x,double v[2]){return s(val[x][0]-v[0])+s(val[x][1]-v[1]);}
47 inline double f(int x,double v[2])
48 {
49     double sum=0;
50     for(int i=0;i<2;++i)
51     {
52         if(minv[x][i]>v[i])sum+=s(minv[x][i]-v[i]);
53         if(maxv[x][i]<v[i])sum+=s(maxv[x][i]-v[i]); 
54     }
55     return sum;
56 }
57 void ask(double v[2],double&ans,int num)
58 {
59     if(!num)return;
60     double d=dis(num,v);
61     if(d>=eps)ans=min(ans,d);
62     double lf=f(son[num][0],v),rf=f(son[num][1],v);
63     if(lf<rf)
64     {
65         if(lf<ans)ask(v,ans,son[num][0]);
66         if(rf<ans)ask(v,ans,son[num][1]);
67     }
68     else
69     {
70         if(rf<ans)ask(v,ans,son[num][1]);
71         if(lf<ans)ask(v,ans,son[num][0]);
72     }
73 }
74 int main()
75 {
76     ios::sync_with_stdio(false);
77     cin>>n;
78     for(int i=1;i<=n;++i)cin>>a[i].v[0]>>a[i].v[1];
79     build(1,n,1,size=1);
80     sort(a+1,a+n+1,cmp2);
81     for(int i=1;i<n;++i)
82     {
83         if(a[i].v[0]==a[i+1].v[0]&&a[i].v[1]==a[i+1].v[1])
84         {
85             cout<<"0.0000"<<endl;
86             return 0;
87         }
88     }
89     ans=inf;
90     for(int i=1;i<=n;++i)
91     {
92         v[0]=a[i].v[0];
93         v[1]=a[i].v[1];
94         ask(v,ans,1);
95     }
96     cout<<fixed<<setprecision(4)<<sqrt(ans)<<endl;
97     return 0; 
98 }
View Code

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

2.求平面最近点对,曼哈顿距离。

  1 #pragma GCC optimize(2)
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 const int maxn=1E6+5;
  5 const int inf=INT_MAX;
  6 int n,m,opt,ans;
  7 int son[maxn][2],val[maxn][2],size,maxv[maxn][2],minv[maxn][2],v[2];
  8 struct pt{int v[2];}a[maxn];
  9 bool cmp0(pt x,pt y){return x.v[0]<y.v[0];}
 10 bool cmp1(pt x,pt y){return x.v[1]<y.v[1];}
 11 inline int read()
 12 {
 13        int w=0,q=0;
 14        char c=getchar();
 15        while((c<'0' || c>'9') && c!='-') c=getchar();
 16        if (c=='-')  q=1, c=getchar();
 17        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
 18        return q ? -w : w;
 19 }
 20 void write(int x)
 21 {
 22     if(x<=9){putchar('0'+x);return;}
 23     write(x/10);
 24     putchar('0'+x%10);
 25 }
 26 inline void update(int x,int y)
 27 {
 28     for(int i=0;i<2;++i)
 29     {
 30         minv[x][i]=min(minv[x][i],minv[y][i]);
 31         maxv[x][i]=max(maxv[x][i],maxv[y][i]);
 32     }
 33 }
 34 void build(int l,int r,int dep,int num)
 35 {
 36     int mid=(l+r)>>1;
 37     if(dep&1)nth_element(a+l,a+mid,a+r+1,cmp1);
 38     else nth_element(a+l,a+mid,a+r+1,cmp0);
 39     maxv[num][0]=minv[num][0]=val[num][0]=a[mid].v[0];
 40     maxv[num][1]=minv[num][1]=val[num][1]=a[mid].v[1];
 41     if(l<=mid-1)
 42     {
 43         build(l,mid-1,dep+1,son[num][0]=++size);
 44         update(num,son[num][0]);
 45     }
 46     if(mid+1<=r)
 47     {
 48         build(mid+1,r,dep+1,son[num][1]=++size);
 49         update(num,son[num][1]);
 50     }
 51 }
 52 void insert(int dep,int num)
 53 {
 54     if(v[dep&1]<=val[num][dep&1])
 55     {
 56         if(son[num][0])insert(dep+1,son[num][0]);
 57         else
 58         {
 59             son[num][0]=++size;
 60             maxv[size][0]=minv[size][0]=val[size][0]=v[0];
 61             maxv[size][1]=minv[size][1]=val[size][1]=v[1];
 62         }
 63         update(num,son[num][0]);
 64     }
 65     else
 66     {
 67         if(son[num][1])insert(dep+1,son[num][1]);
 68         else
 69         {
 70             son[num][1]=++size;
 71             maxv[size][0]=minv[size][0]=val[size][0]=v[0];
 72             maxv[size][1]=minv[size][1]=val[size][1]=v[1];
 73         }
 74         update(num,son[num][1]);
 75     }
 76 }
 77 inline int f(int x)
 78 {
 79     int sum=0;
 80     for(int i=0;i<2;++i)
 81     {
 82         if(minv[x][i]>v[i])sum+=minv[x][i]-v[i];
 83         if(maxv[x][i]<v[i])sum+=v[i]-maxv[x][i];
 84     }
 85     return sum;
 86 }
 87 inline int dis(int x){return abs(val[x][0]-v[0])+abs(val[x][1]-v[1]);}
 88 void ask(int&ans,int num)
 89 {
 90     if(num==0)return;
 91     ans=min(ans,dis(num));
 92     int lf=f(son[num][0]),rf=f(son[num][1]);
 93     if(lf<rf)
 94     {
 95         if(lf<ans)ask(ans,son[num][0]);
 96         if(rf<ans)ask(ans,son[num][1]);
 97     }
 98     else
 99     {
100         if(rf<ans)ask(ans,son[num][1]);
101         if(lf<ans)ask(ans,son[num][0]); 
102     }
103 }
104 void out(int num,int dep)
105 {
106     if(num==0)return;
107     cout.width(6*dep);
108     cout<<val[num][0]<<" "<<val[num][1]<<endl;
109     out(son[num][0],dep+1);
110     out(son[num][1],dep+1);
111 }
112 int main()
113 {
114     ios::sync_with_stdio(false);
115     n=read();m=read();
116     for(int i=1;i<=n;++i)a[i].v[0]=read(),a[i].v[1]=read();
117     build(1,n,1,size=1);
118     while(m--)
119     {
120         opt=read(),v[0]=read(),v[1]=read();
121         if(opt==1)insert(1,1);
122         else
123         {
124             ans=inf;
125             ask(ans,1);
126             write(ans);
127             putchar('\n');
128         }
129 //        out(1,0);
130     }
131     return 0;
132 }
View Code

https://www.lydsy.com/JudgeOnline/problem.php?id=2648

洛咕上T了。

3.求平面最远点对。精确到小数点后4位。

换个估价函数就行了,没代码。

4.求平面上k远点对。给出距离的平方,n≤100,000,k≤100。

博主的做法类似于超级钢琴和异或粽子的做法,先将所有的点的最远距离加入大根堆,每次取出最大元素,更新其次大的答案。

在查询过程中,为了防止访问到之前的答案,hash一下。

不要偷懒用map。1.6s--->16s。

  1 #include<bits/stdc++.h>
  2 #define mod 10000007
  3 #define p 13131
  4 using namespace std;
  5 typedef long long int ll;
  6 const ll maxn=1E5+5;
  7 const ll inf=LONG_LONG_MAX;
  8 
  9 ll min(ll x,ll y){return x<y?x:y;}
 10 ll max(ll x,ll y){return x>y?x:y;}
 11 
 12 int son[maxn][2],n,k,m,size;
 13 ll val[maxn][2],maxv[maxn][2],minv[maxn][2],v[2],ans,pos;
 14 
 15 struct p1{ll v[2];}a[maxn];
 16 bool vis[mod];
 17 int M(int x,int y){return (x*p+y)%mod;}
 18 bool cmp0(p1 x,p1 y){return x.v[0]<y.v[0];}
 19 bool cmp1(p1 x,p1 y){return x.v[1]<y.v[1];}
 20 struct pt{int pos;ll ans;};
 21 struct _cmp{bool operator()(pt x,pt y)const{return x.ans<y.ans;}};
 22 
 23 priority_queue<pt,vector<pt>,_cmp>Q;
 24 
 25 inline int read()
 26 {
 27        int w=0,q=0;
 28        char c=getchar();
 29        while((c<'0' || c>'9') && c!='-') c=getchar();
 30        if (c=='-')  q=1, c=getchar();
 31        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
 32        return q ? -w : w;
 33 }
 34 
 35 void update(int x,int y)
 36 {
 37     for(int i=0;i<2;++i)
 38     {
 39         minv[x][i]=min(minv[x][i],minv[y][i]);
 40         maxv[x][i]=max(maxv[x][i],maxv[y][i]);
 41     }
 42 }
 43 void build(int l,int r,int dep,int num)
 44 {
 45     int mid=(l+r)>>1;
 46     if(dep&1)nth_element(a+l,a+mid,a+r+1,cmp0);
 47     else nth_element(a+l,a+mid,a+r+1,cmp1);
 48     minv[num][0]=maxv[num][0]=val[num][0]=a[mid].v[0];
 49     minv[num][1]=maxv[num][1]=val[num][1]=a[mid].v[1];
 50     if(l<=mid-1)
 51     {
 52         build(l,mid-1,dep+1,son[num][0]=++size);
 53         update(num,son[num][0]);
 54     }
 55     if(mid+1<=r)
 56     {
 57         build(mid+1,r,dep+1,son[num][1]=++size);
 58         update(num,son[num][1]);
 59     }
 60 }
 61 inline ll s(ll x){return x*x;}
 62 inline ll f(int x)
 63 {
 64     if(x==0)return inf;
 65     ll sum=0;
 66     for(int i=0;i<2;++i)
 67     {
 68         if(v[i]<maxv[x][i])sum+=s(maxv[x][i]-v[i]);
 69         if(minv[x][i]<v[i])sum+=s(minv[x][i]-v[i]);
 70     }
 71     return sum;
 72 }
 73 inline ll dis(int x){return s(val[x][0]-v[0])+s(val[x][1]-v[1]);}
 74 void ask(int num,int g,ll&ans)
 75 {
 76     if(num==0)return;
 77     ll d=dis(num);
 78     if(!vis[M(g,num)]&&ans<d)
 79     {
 80         ans=d;
 81         pos=num;
 82     }
 83     ll lf=f(son[num][0]),rf=f(son[num][1]);
 84     if(lf>rf)
 85     {
 86         if(lf>ans)ask(son[num][0],g,ans);
 87         if(rf>ans)ask(son[num][1],g,ans);
 88     }
 89     else
 90     {
 91         if(rf>ans)ask(son[num][1],g,ans);
 92         if(lf>ans)ask(son[num][0],g,ans);
 93     }
 94 }
 95 int main()
 96 {
 97 //    freopen("a.in","r",stdin);
 98     ios::sync_with_stdio(false);
 99     n=read();k=read();
100     for(int i=1;i<=n;++i)a[i].v[0]=read(),a[i].v[1]=read();
101     build(1,n,1,size=1);
102     for(int i=1;i<=n;++i)
103     {
104         v[0]=a[i].v[0];
105         v[1]=a[i].v[1];
106         ans=-1;
107         ask(1,i,ans);
108         vis[M(i,pos)]=1;
109         Q.push((pt){i,ans});
110     }
111     k=2*k;
112     ll hhh=0;
113     while(k--)
114     {
115         pt u=Q.top();
116         Q.pop();
117         hhh=u.ans;
118         v[0]=a[u.pos].v[0];
119         v[1]=a[u.pos].v[1];
120         ans=-1;
121         ask(1,u.pos,ans);
122         vis[M(u.pos,pos)]=1;
123         Q.push((pt){u.pos,ans});
124     }
125     cout<<hhh<<endl;
126     return 0;
127 }
View Code

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

猜你喜欢

转载自www.cnblogs.com/GreenDuck/p/10719548.html