在竞赛中,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

 

5.两种操作,一种在平面上添加一个点,一种询问矩形区域内的权值和,允许离线。

离线建树,询问时判断某个点范围内的矩形是否在询问中即可。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=2E5+5;
  4 const int inf=2000005;
  5 const double d=0.75;
  6 
  7 int n,m,size,cur,opt;
  8 int son[maxn][2],val[maxn][2],sum[maxn],sumW[maxn],w[maxn],fa[maxn];
  9 
 10 struct rect{int l,r,u,d;}range[maxn];
 11 struct pt{int v[2];}a[maxn];
 12 struct query{int a[5];}Q[maxn];
 13 
 14 bool cmp0(pt x,pt y){return x.v[0]<y.v[0];}
 15 bool cmp1(pt x,pt y){return x.v[1]<y.v[1];}
 16 bool in(rect A,rect B){return (B.l<=A.l)&&(A.r<=B.r)&&(A.u<=B.u)&&(B.d<=A.d);}
 17 bool out(rect A,rect B){return (B.r<A.l)||(A.r<B.l)||(B.u<A.d)||(A.u<B.d);}
 18 bool inDot(rect A,int x,int y){return (A.l<=x)&&(x<=A.r)&&(A.d<=y)&&(y<=A.u);}
 19 
 20 map<pair<int,int>,bool>vis;
 21 map<pair<int,int>,int>where;
 22 pair<int,int> M(int x,int y){return make_pair(x,y);}
 23 
 24 void build(int l,int r,int dep,int num)
 25 {
 26     int mid=(l+r)>>1;
 27     if(dep&1)nth_element(a+l,a+mid,a+r+1,cmp0);
 28     else nth_element(a+l,a+mid,a+r+1,cmp1);
 29     val[num][0]=a[mid].v[0];
 30     val[num][1]=a[mid].v[1];
 31     where[M(val[num][0],val[num][1])]=num;
 32 //    cout.width(14*dep-14);
 33 //    cout<<val[num][0]<<' '<<val[num][1]<<' '<<range[num].l<<' '<<range[num].r<<' '<<range[num].u<<' '<<range[num].d<<endl;
 34     if(l<=mid-1)
 35     {
 36         son[num][0]=++size;
 37         if(dep&1)range[son[num][0]]=(rect){range[num].l,val[num][0],range[num].u,range[num].d};
 38         else range[son[num][0]]=(rect){range[num].l,range[num].r,val[num][1],range[num].d};
 39         fa[size]=num;
 40         build(l,mid-1,dep+1,size);
 41     }
 42     if(mid+1<=r)
 43     {
 44         son[num][1]=++size;
 45         if(dep&1)range[son[num][1]]=(rect){val[num][0],range[num].r,range[num].u,range[num].d};
 46         else range[son[num][1]]=(rect){range[num].l,range[num].r,range[num].u,val[num][1]};
 47         fa[size]=num;
 48         build(mid+1,r,dep+1,size);
 49     }
 50 }
 51 int ask(rect R,int num)
 52 {
 53     if(num==0)return 0;
 54     if(in(range[num],R))return sumW[num];
 55     else if(out(range[num],R))return 0;
 56     int ans=0;
 57     if(inDot(R,val[num][0],val[num][1]))ans+=w[num];
 58     return ask(R,son[num][0])+ask(R,son[num][1])+ans;
 59 }
 60 void add(int x,int num)
 61 {
 62     if(num==0)return;
 63     sumW[num]+=x;
 64     add(x,fa[num]);
 65 }
 66 int main()
 67 {
 68     ios::sync_with_stdio(false);
 69     cin>>n>>n;
 70     while(true)
 71     {
 72         cin>>opt;
 73         if(opt==3)break;
 74         ++m;
 75         if(opt==1)
 76         {
 77             ++cur;
 78             cin>>a[cur].v[0]>>a[cur].v[1]>>Q[m].a[3];
 79             Q[m].a[1]=a[cur].v[0];
 80             Q[m].a[2]=a[cur].v[1];
 81             Q[m].a[0]=1;
 82             if(vis[M(a[cur].v[0],a[cur].v[1])])--cur;
 83             vis[M(a[cur].v[0],a[cur].v[1])]=1;
 84         }
 85         else
 86         {
 87             Q[m].a[0]=2;
 88             cin>>Q[m].a[1]>>Q[m].a[2]>>Q[m].a[3]>>Q[m].a[4];
 89         }
 90     }
 91     range[size=1]=(rect){1,n,n,1};
 92     build(1,cur,1,1);
 93     for(int i=1;i<=m;++i)
 94     {
 95         if(Q[i].a[0]==1)
 96         {
 97             add(Q[i].a[3],where[M(Q[i].a[1],Q[i].a[2])]);
 98             w[where[M(Q[i].a[1],Q[i].a[2])]]+=Q[i].a[3]; 
 99         }
100         else cout<<ask((rect){Q[i].a[1],Q[i].a[3],Q[i].a[4],Q[i].a[2]},1)<<endl;
101     }
102     return 0;
103 }
View Code

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

 

6.两种操作,一种在矩形区域内点的权值加上给定值,一种询问历史最小值。

多维护个tag和minTag,由于修改是连续的,minTag相当于维护的是最小前缀和。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long int ll;
  4 const int maxn=1E5+5;
  5 const int inf=123456789;
  6 int n,m,tot;
  7 int TI,son[maxn][2],X[maxn],Y[maxn],fa[maxn];
  8 int minn[maxn][2],maxx[maxn][2];
  9 ll a[maxn],sum[maxn],val[maxn],valhis[maxn],tag[maxn],taghis[maxn];
 10 map<pair<int,int>,int>where;
 11 struct query
 12 {
 13     int opt,x,y;
 14 }Q[maxn];
 15 struct pt
 16 {
 17     int x,y;
 18 }wait[maxn];
 19 bool cmp1(const pt&A,const pt&B)
 20 {
 21     return A.x<B.x;
 22 }
 23 bool cmp2(const pt&A,const pt&B)
 24 {
 25     return A.y<B.y;
 26 }
 27 inline void hh(int x,int y)
 28 {
 29     if(!y)
 30         return;
 31     minn[x][0]=min(minn[x][0],minn[y][0]);
 32     minn[x][1]=min(minn[x][1],minn[y][1]);
 33     maxx[x][0]=max(maxx[x][0],maxx[y][0]);
 34     maxx[x][1]=max(maxx[x][1],maxx[y][1]);
 35 }
 36 void build(int l,int r,int dep,int&num)
 37 {
 38     if(l>r)
 39         return;
 40     num=++TI;
 41     int mid=(l+r)>>1;
 42     if(dep&1)
 43         nth_element(wait+l,wait+mid,wait+r+1,cmp1);
 44     else
 45         nth_element(wait+l,wait+mid,wait+r+1,cmp2);
 46     valhis[num]=val[num]=sum[wait[mid].y]-sum[wait[mid].x-1];
 47     X[num]=wait[mid].x,Y[num]=wait[mid].y;
 48     where[make_pair(X[num],Y[num])]=num;
 49     minn[num][0]=maxx[num][0]=wait[mid].x;
 50     minn[num][1]=maxx[num][1]=wait[mid].y;
 51     if(dep&1)
 52     {
 53         build(l,mid-1,dep+1,son[num][0]);
 54         fa[son[num][0]]=num;
 55         build(mid+1,r,dep+1,son[num][1]);
 56         fa[son[num][1]]=num;
 57     }
 58     else
 59     {
 60         build(l,mid-1,dep+1,son[num][0]);
 61         fa[son[num][0]]=num;
 62         build(mid+1,r,dep+1,son[num][1]);
 63         fa[son[num][1]]=num;
 64     }
 65     hh(num,son[num][0]);
 66     hh(num,son[num][1]);
 67 }
 68 inline void get(int x,int y)
 69 {
 70     valhis[x]=min(valhis[x],val[x]+taghis[y]);
 71     val[x]+=tag[y];
 72     taghis[x]=min(taghis[x],tag[x]+taghis[y]);
 73     tag[x]+=tag[y];
 74 }
 75 inline void pushdown(int num)
 76 {
 77     if(son[num][0])
 78         get(son[num][0],num);
 79     if(son[num][1])
 80         get(son[num][1],num);
 81     tag[num]=taghis[num]=0;
 82 }
 83 void change(int num,ll x,int p)
 84 {
 85     if(!num||minn[num][0]>p||maxx[num][1]<p)
 86         return;
 87     if(maxx[num][0]<=p&&minn[num][1]>=p)
 88     {
 89         tag[num]+=x;
 90         taghis[num]=min(taghis[num],tag[num]);
 91         val[num]+=x;
 92         valhis[num]=min(valhis[num],val[num]);
 93         pushdown(num);
 94         return;
 95     }
 96     if(X[num]<=p&&p<=Y[num])
 97     {
 98         val[num]+=x;
 99         valhis[num]=min(valhis[num],val[num]);
100     }
101     pushdown(num);
102     change(son[num][0],x,p);
103     change(son[num][1],x,p);
104 }
105 void update(int num)
106 {
107     if(!num)
108         return;
109     update(fa[num]);
110     pushdown(num);
111 }
112 int main()
113 {
114     ios::sync_with_stdio(false);
115     cin>>n>>m;
116     for(int i=1;i<=n;++i)
117     {
118         cin>>a[i];
119         sum[i]=sum[i-1]+a[i];
120     }
121     map<pair<int,int>,bool>vis;
122     for(int i=1;i<=m;++i)
123     {
124         cin>>Q[i].opt>>Q[i].x>>Q[i].y;
125         if(Q[i].opt==2&&!vis[make_pair(Q[i].x,Q[i].y)])
126         {
127             wait[++tot]=(pt){Q[i].x,Q[i].y};
128             vis[make_pair(Q[i].x,Q[i].y)]=1;
129         }
130     }
131     int x=0;
132     build(1,tot,0,x);
133     for(int i=1;i<=m;++i)
134     {
135         int opt=Q[i].opt,x=Q[i].x,y=Q[i].y;
136         if(opt==1)
137         {
138             ll d=y-a[x];
139             a[x]=y;
140             change(1,d,x);
141         }
142         else
143         {
144             update(where[make_pair(x,y)]);
145             cout<<valhis[where[make_pair(x,y)]]<<endl;
146         }
147     }
148     return 0;
149 }
View Code

 

 posted on 2019-04-16 19:48  GreenDuck  阅读(597)  评论(0编辑  收藏  举报