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

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

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

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

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

模板,不解释。

 // luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const double eps=0.00001;
const double inf=1E18;
const int maxn=2E5+;
int n,m;
int son[maxn][],size;
double val[maxn][],minv[maxn][],maxv[maxn][],ans,v[];
struct pt{double v[];}a[maxn];
bool cmp0(pt x,pt y){return x.v[]<y.v[];}
bool cmp1(pt x,pt y){return x.v[]<y.v[];}
bool cmp2(pt x,pt y)
{
if(x.v[]==y.v[])return x.v[]<y.v[];
return x.v[]<y.v[];
}
inline void update(int x,int y)
{
for(int i=;i<;++i)
{
minv[x][i]=min(minv[x][i],minv[y][i]);
maxv[x][i]=max(maxv[x][i],maxv[y][i]);
}
}
void build(int l,int r,int dep,int num)
{
int mid=(l+r)>>;
if(dep%==)nth_element(a+l,a+mid,a+r+,cmp0);
else nth_element(a+l,a+mid,a+r+,cmp1);
minv[num][]=maxv[num][]=val[num][]=a[mid].v[];
minv[num][]=maxv[num][]=val[num][]=a[mid].v[];
if(l<=mid-)
{
build(l,mid-,dep+,son[num][]=++size);
update(num,son[num][]);
}
if(mid+<=r)
{
build(mid+,r,dep+,son[num][]=++size);
update(num,son[num][]);
}
}
inline double s(double x){return x*x;}
inline double dis(int x,double v[]){return s(val[x][]-v[])+s(val[x][]-v[]);}
inline double f(int x,double v[])
{
double sum=;
for(int i=;i<;++i)
{
if(minv[x][i]>v[i])sum+=s(minv[x][i]-v[i]);
if(maxv[x][i]<v[i])sum+=s(maxv[x][i]-v[i]);
}
return sum;
}
void ask(double v[],double&ans,int num)
{
if(!num)return;
double d=dis(num,v);
if(d>=eps)ans=min(ans,d);
double lf=f(son[num][],v),rf=f(son[num][],v);
if(lf<rf)
{
if(lf<ans)ask(v,ans,son[num][]);
if(rf<ans)ask(v,ans,son[num][]);
}
else
{
if(rf<ans)ask(v,ans,son[num][]);
if(lf<ans)ask(v,ans,son[num][]);
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=;i<=n;++i)cin>>a[i].v[]>>a[i].v[];
build(,n,,size=);
sort(a+,a+n+,cmp2);
for(int i=;i<n;++i)
{
if(a[i].v[]==a[i+].v[]&&a[i].v[]==a[i+].v[])
{
cout<<"0.0000"<<endl;
return ;
}
}
ans=inf;
for(int i=;i<=n;++i)
{
v[]=a[i].v[];
v[]=a[i].v[];
ask(v,ans,);
}
cout<<fixed<<setprecision()<<sqrt(ans)<<endl;
return ;
}

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

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

 #pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1E6+;
const int inf=INT_MAX;
int n,m,opt,ans;
int son[maxn][],val[maxn][],size,maxv[maxn][],minv[maxn][],v[];
struct pt{int v[];}a[maxn];
bool cmp0(pt x,pt y){return x.v[]<y.v[];}
bool cmp1(pt x,pt y){return x.v[]<y.v[];}
inline int read()
{
int w=,q=;
char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar();
if (c=='-') q=, c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar();
return q ? -w : w;
}
void write(int x)
{
if(x<=){putchar(''+x);return;}
write(x/);
putchar(''+x%);
}
inline void update(int x,int y)
{
for(int i=;i<;++i)
{
minv[x][i]=min(minv[x][i],minv[y][i]);
maxv[x][i]=max(maxv[x][i],maxv[y][i]);
}
}
void build(int l,int r,int dep,int num)
{
int mid=(l+r)>>;
if(dep&)nth_element(a+l,a+mid,a+r+,cmp1);
else nth_element(a+l,a+mid,a+r+,cmp0);
maxv[num][]=minv[num][]=val[num][]=a[mid].v[];
maxv[num][]=minv[num][]=val[num][]=a[mid].v[];
if(l<=mid-)
{
build(l,mid-,dep+,son[num][]=++size);
update(num,son[num][]);
}
if(mid+<=r)
{
build(mid+,r,dep+,son[num][]=++size);
update(num,son[num][]);
}
}
void insert(int dep,int num)
{
if(v[dep&]<=val[num][dep&])
{
if(son[num][])insert(dep+,son[num][]);
else
{
son[num][]=++size;
maxv[size][]=minv[size][]=val[size][]=v[];
maxv[size][]=minv[size][]=val[size][]=v[];
}
update(num,son[num][]);
}
else
{
if(son[num][])insert(dep+,son[num][]);
else
{
son[num][]=++size;
maxv[size][]=minv[size][]=val[size][]=v[];
maxv[size][]=minv[size][]=val[size][]=v[];
}
update(num,son[num][]);
}
}
inline int f(int x)
{
int sum=;
for(int i=;i<;++i)
{
if(minv[x][i]>v[i])sum+=minv[x][i]-v[i];
if(maxv[x][i]<v[i])sum+=v[i]-maxv[x][i];
}
return sum;
}
inline int dis(int x){return abs(val[x][]-v[])+abs(val[x][]-v[]);}
void ask(int&ans,int num)
{
if(num==)return;
ans=min(ans,dis(num));
int lf=f(son[num][]),rf=f(son[num][]);
if(lf<rf)
{
if(lf<ans)ask(ans,son[num][]);
if(rf<ans)ask(ans,son[num][]);
}
else
{
if(rf<ans)ask(ans,son[num][]);
if(lf<ans)ask(ans,son[num][]);
}
}
void out(int num,int dep)
{
if(num==)return;
cout.width(*dep);
cout<<val[num][]<<" "<<val[num][]<<endl;
out(son[num][],dep+);
out(son[num][],dep+);
}
int main()
{
ios::sync_with_stdio(false);
n=read();m=read();
for(int i=;i<=n;++i)a[i].v[]=read(),a[i].v[]=read();
build(,n,,size=);
while(m--)
{
opt=read(),v[]=read(),v[]=read();
if(opt==)insert(,);
else
{
ans=inf;
ask(ans,);
write(ans);
putchar('\n');
}
// out(1,0);
}
return ;
}

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

洛咕上T了。

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

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

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

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

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

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

 #include<bits/stdc++.h>
#define mod 10000007
#define p 13131
using namespace std;
typedef long long int ll;
const ll maxn=1E5+;
const ll inf=LONG_LONG_MAX; ll min(ll x,ll y){return x<y?x:y;}
ll max(ll x,ll y){return x>y?x:y;} int son[maxn][],n,k,m,size;
ll val[maxn][],maxv[maxn][],minv[maxn][],v[],ans,pos; struct p1{ll v[];}a[maxn];
bool vis[mod];
int M(int x,int y){return (x*p+y)%mod;}
bool cmp0(p1 x,p1 y){return x.v[]<y.v[];}
bool cmp1(p1 x,p1 y){return x.v[]<y.v[];}
struct pt{int pos;ll ans;};
struct _cmp{bool operator()(pt x,pt y)const{return x.ans<y.ans;}}; priority_queue<pt,vector<pt>,_cmp>Q; inline int read()
{
int w=,q=;
char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar();
if (c=='-') q=, c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar();
return q ? -w : w;
} void update(int x,int y)
{
for(int i=;i<;++i)
{
minv[x][i]=min(minv[x][i],minv[y][i]);
maxv[x][i]=max(maxv[x][i],maxv[y][i]);
}
}
void build(int l,int r,int dep,int num)
{
int mid=(l+r)>>;
if(dep&)nth_element(a+l,a+mid,a+r+,cmp0);
else nth_element(a+l,a+mid,a+r+,cmp1);
minv[num][]=maxv[num][]=val[num][]=a[mid].v[];
minv[num][]=maxv[num][]=val[num][]=a[mid].v[];
if(l<=mid-)
{
build(l,mid-,dep+,son[num][]=++size);
update(num,son[num][]);
}
if(mid+<=r)
{
build(mid+,r,dep+,son[num][]=++size);
update(num,son[num][]);
}
}
inline ll s(ll x){return x*x;}
inline ll f(int x)
{
if(x==)return inf;
ll sum=;
for(int i=;i<;++i)
{
if(v[i]<maxv[x][i])sum+=s(maxv[x][i]-v[i]);
if(minv[x][i]<v[i])sum+=s(minv[x][i]-v[i]);
}
return sum;
}
inline ll dis(int x){return s(val[x][]-v[])+s(val[x][]-v[]);}
void ask(int num,int g,ll&ans)
{
if(num==)return;
ll d=dis(num);
if(!vis[M(g,num)]&&ans<d)
{
ans=d;
pos=num;
}
ll lf=f(son[num][]),rf=f(son[num][]);
if(lf>rf)
{
if(lf>ans)ask(son[num][],g,ans);
if(rf>ans)ask(son[num][],g,ans);
}
else
{
if(rf>ans)ask(son[num][],g,ans);
if(lf>ans)ask(son[num][],g,ans);
}
}
int main()
{
// freopen("a.in","r",stdin);
ios::sync_with_stdio(false);
n=read();k=read();
for(int i=;i<=n;++i)a[i].v[]=read(),a[i].v[]=read();
build(,n,,size=);
for(int i=;i<=n;++i)
{
v[]=a[i].v[];
v[]=a[i].v[];
ans=-;
ask(,i,ans);
vis[M(i,pos)]=;
Q.push((pt){i,ans});
}
k=*k;
ll hhh=;
while(k--)
{
pt u=Q.top();
Q.pop();
hhh=u.ans;
v[]=a[u.pos].v[];
v[]=a[u.pos].v[];
ans=-;
ask(,u.pos,ans);
vis[M(u.pos,pos)]=;
Q.push((pt){u.pos,ans});
}
cout<<hhh<<endl;
return ;
}

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

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

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

 #include<bits/stdc++.h>
using namespace std;
const int maxn=2E5+;
const int inf=;
const double d=0.75; int n,m,size,cur,opt;
int son[maxn][],val[maxn][],sum[maxn],sumW[maxn],w[maxn],fa[maxn]; struct rect{int l,r,u,d;}range[maxn];
struct pt{int v[];}a[maxn];
struct query{int a[];}Q[maxn]; bool cmp0(pt x,pt y){return x.v[]<y.v[];}
bool cmp1(pt x,pt y){return x.v[]<y.v[];}
bool in(rect A,rect B){return (B.l<=A.l)&&(A.r<=B.r)&&(A.u<=B.u)&&(B.d<=A.d);}
bool out(rect A,rect B){return (B.r<A.l)||(A.r<B.l)||(B.u<A.d)||(A.u<B.d);}
bool inDot(rect A,int x,int y){return (A.l<=x)&&(x<=A.r)&&(A.d<=y)&&(y<=A.u);} map<pair<int,int>,bool>vis;
map<pair<int,int>,int>where;
pair<int,int> M(int x,int y){return make_pair(x,y);} void build(int l,int r,int dep,int num)
{
int mid=(l+r)>>;
if(dep&)nth_element(a+l,a+mid,a+r+,cmp0);
else nth_element(a+l,a+mid,a+r+,cmp1);
val[num][]=a[mid].v[];
val[num][]=a[mid].v[];
where[M(val[num][],val[num][])]=num;
// cout.width(14*dep-14);
// cout<<val[num][0]<<' '<<val[num][1]<<' '<<range[num].l<<' '<<range[num].r<<' '<<range[num].u<<' '<<range[num].d<<endl;
if(l<=mid-)
{
son[num][]=++size;
if(dep&)range[son[num][]]=(rect){range[num].l,val[num][],range[num].u,range[num].d};
else range[son[num][]]=(rect){range[num].l,range[num].r,val[num][],range[num].d};
fa[size]=num;
build(l,mid-,dep+,size);
}
if(mid+<=r)
{
son[num][]=++size;
if(dep&)range[son[num][]]=(rect){val[num][],range[num].r,range[num].u,range[num].d};
else range[son[num][]]=(rect){range[num].l,range[num].r,range[num].u,val[num][]};
fa[size]=num;
build(mid+,r,dep+,size);
}
}
int ask(rect R,int num)
{
if(num==)return ;
if(in(range[num],R))return sumW[num];
else if(out(range[num],R))return ;
int ans=;
if(inDot(R,val[num][],val[num][]))ans+=w[num];
return ask(R,son[num][])+ask(R,son[num][])+ans;
}
void add(int x,int num)
{
if(num==)return;
sumW[num]+=x;
add(x,fa[num]);
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>n;
while(true)
{
cin>>opt;
if(opt==)break;
++m;
if(opt==)
{
++cur;
cin>>a[cur].v[]>>a[cur].v[]>>Q[m].a[];
Q[m].a[]=a[cur].v[];
Q[m].a[]=a[cur].v[];
Q[m].a[]=;
if(vis[M(a[cur].v[],a[cur].v[])])--cur;
vis[M(a[cur].v[],a[cur].v[])]=;
}
else
{
Q[m].a[]=;
cin>>Q[m].a[]>>Q[m].a[]>>Q[m].a[]>>Q[m].a[];
}
}
range[size=]=(rect){,n,n,};
build(,cur,,);
for(int i=;i<=m;++i)
{
if(Q[i].a[]==)
{
add(Q[i].a[],where[M(Q[i].a[],Q[i].a[])]);
w[where[M(Q[i].a[],Q[i].a[])]]+=Q[i].a[];
}
else cout<<ask((rect){Q[i].a[],Q[i].a[],Q[i].a[],Q[i].a[]},)<<endl;
}
return ;
}

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

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

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

 #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int maxn=1E5+;
const int inf=;
int n,m,tot;
int TI,son[maxn][],X[maxn],Y[maxn],fa[maxn];
int minn[maxn][],maxx[maxn][];
ll a[maxn],sum[maxn],val[maxn],valhis[maxn],tag[maxn],taghis[maxn];
map<pair<int,int>,int>where;
struct query
{
int opt,x,y;
}Q[maxn];
struct pt
{
int x,y;
}wait[maxn];
bool cmp1(const pt&A,const pt&B)
{
return A.x<B.x;
}
bool cmp2(const pt&A,const pt&B)
{
return A.y<B.y;
}
inline void hh(int x,int y)
{
if(!y)
return;
minn[x][]=min(minn[x][],minn[y][]);
minn[x][]=min(minn[x][],minn[y][]);
maxx[x][]=max(maxx[x][],maxx[y][]);
maxx[x][]=max(maxx[x][],maxx[y][]);
}
void build(int l,int r,int dep,int&num)
{
if(l>r)
return;
num=++TI;
int mid=(l+r)>>;
if(dep&)
nth_element(wait+l,wait+mid,wait+r+,cmp1);
else
nth_element(wait+l,wait+mid,wait+r+,cmp2);
valhis[num]=val[num]=sum[wait[mid].y]-sum[wait[mid].x-];
X[num]=wait[mid].x,Y[num]=wait[mid].y;
where[make_pair(X[num],Y[num])]=num;
minn[num][]=maxx[num][]=wait[mid].x;
minn[num][]=maxx[num][]=wait[mid].y;
if(dep&)
{
build(l,mid-,dep+,son[num][]);
fa[son[num][]]=num;
build(mid+,r,dep+,son[num][]);
fa[son[num][]]=num;
}
else
{
build(l,mid-,dep+,son[num][]);
fa[son[num][]]=num;
build(mid+,r,dep+,son[num][]);
fa[son[num][]]=num;
}
hh(num,son[num][]);
hh(num,son[num][]);
}
inline void get(int x,int y)
{
valhis[x]=min(valhis[x],val[x]+taghis[y]);
val[x]+=tag[y];
taghis[x]=min(taghis[x],tag[x]+taghis[y]);
tag[x]+=tag[y];
}
inline void pushdown(int num)
{
if(son[num][])
get(son[num][],num);
if(son[num][])
get(son[num][],num);
tag[num]=taghis[num]=;
}
void change(int num,ll x,int p)
{
if(!num||minn[num][]>p||maxx[num][]<p)
return;
if(maxx[num][]<=p&&minn[num][]>=p)
{
tag[num]+=x;
taghis[num]=min(taghis[num],tag[num]);
val[num]+=x;
valhis[num]=min(valhis[num],val[num]);
pushdown(num);
return;
}
if(X[num]<=p&&p<=Y[num])
{
val[num]+=x;
valhis[num]=min(valhis[num],val[num]);
}
pushdown(num);
change(son[num][],x,p);
change(son[num][],x,p);
}
void update(int num)
{
if(!num)
return;
update(fa[num]);
pushdown(num);
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=;i<=n;++i)
{
cin>>a[i];
sum[i]=sum[i-]+a[i];
}
map<pair<int,int>,bool>vis;
for(int i=;i<=m;++i)
{
cin>>Q[i].opt>>Q[i].x>>Q[i].y;
if(Q[i].opt==&&!vis[make_pair(Q[i].x,Q[i].y)])
{
wait[++tot]=(pt){Q[i].x,Q[i].y};
vis[make_pair(Q[i].x,Q[i].y)]=;
}
}
int x=;
build(,tot,,x);
for(int i=;i<=m;++i)
{
int opt=Q[i].opt,x=Q[i].x,y=Q[i].y;
if(opt==)
{
ll d=y-a[x];
a[x]=y;
change(,d,x);
}
else
{
update(where[make_pair(x,y)]);
cout<<valhis[where[make_pair(x,y)]]<<endl;
}
}
return ;
}

kd-tree题目总结的更多相关文章

  1. K-D Tree题目泛做(CXJ第二轮)

    题目1: BZOJ 2716 题目大意:给出N个二维平面上的点,M个操作,分为插入一个新点和询问到一个点最近点的Manhatan距离是多少. 算法讨论: K-D Tree 裸题,有插入操作. #inc ...

  2. k-d tree 学习笔记

    以下是一些奇怪的链接有兴趣的可以看看: https://blog.sengxian.com/algorithms/k-dimensional-tree http://zgjkt.blog.uoj.ac ...

  3. k-d tree模板练习

    1. [BZOJ]1941: [Sdoi2010]Hide and Seek 题目大意:给出n个二维平面上的点,一个点的权值是它到其他点的最长距离减最短距离,距离为曼哈顿距离,求最小权值.(n< ...

  4. BZOJ5465: [APIO 2018] 选圆圈(K-D Tree)

    题意 题目链接 Sol 下面是错误做法,正解请看这里 考虑直接用K-D tree模拟.. 刚开始想的是维护矩形最大最小值,以及子树中最大圆的位置,然后... 实际上最大圆的位置是不用维护的,直接把原序 ...

  5. BZOJ 3489: A simple rmq problem(K-D Tree)

    Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 2579  Solved: 888[Submit][Status][Discuss] Descripti ...

  6. 初涉k-d tree

    听说k-d tree是一个骗分的好东西?(但是复杂度差评??? 还听说绍一的kdt常数特别小? KDT是什么 KDT的全称是k-degree tree,顾名思义,这是一种处理多维空间的数据结构. 例如 ...

  7. AOJ DSL_2_C Range Search (kD Tree)

    Range Search (kD Tree) The range search problem consists of a set of attributed records S to determi ...

  8. 【BZOJ-2648&2716】SJY摆棋子&天使玩偶 KD Tree

    2648: SJY摆棋子 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2459  Solved: 834[Submit][Status][Discu ...

  9. K-D Tree

    这篇随笔是对Wikipedia上k-d tree词条的摘录, 我认为解释得相当生动详细, 是一篇不可多得的好文. Overview A \(k\)-d tree (short for \(k\)-di ...

  10. k-d Tree in TripAdvisor

    Today, TripAdvisor held a tech talk in Columbia University. The topic is about k-d Tree implemented ...

随机推荐

  1. 自制操作系统Antz(13) 显示图片

    显示图片只是在多媒体课上看着bmp格式图片的突发奇想,然后就实现在了我自己的操作系统 Antz系统更新地址 Linux内核源码分析地址 Github项目地址 效果图: 显示图片的原理 在之前显卡操作时 ...

  2. Scrum Meeting 合集

    一.Alpha [Alpha]Scrum meeting 1 [Alpha]Scrum meeting 2 [Alpha]Scrum meeting 3 [Alpha]Scrum meeting 4 ...

  3. Selenium及Headless Chrome抓取动态HTML页面

    一般的的静态HTML页面可以使用requests等库直接抓取,但还有一部分比较复杂的动态页面,这些页面的DOM是动态生成的,有些还需要用户与其点击互动,这些页面只能使用真实的浏览器引擎动态解析,Sel ...

  4. SPOJ DQUERY D-query(主席树 区间不同数个数)

    题意:问你区间有几个不同的数 思路:主席树nb.我们知道主席树每一个root都存着一棵权值线段树,现在我们在每个root中存位置,也就是01表示这个位置存不存在.然后我们用一个fa[a[i]]表示a[ ...

  5. 3、Docker镜像管理基础

    Docker image     # docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE redis -alpine 23d561d12e92 d ...

  6. 让小乌龟可以唱歌——对Python turtle进行拓展

    在Scratch中,小猫是可以唱歌的,而且Scratch的声音木块有着丰富的功能,在这方面Python turtle略有欠缺,今天我们就来完善一下. Python声音模块 Python处理声音的模块很 ...

  7. SSH实现ajax

    (1)首先要引入需要pom文件 <!-- https://mvnrepository.com/artifact/org.apache.struts/struts2-json-plugin --& ...

  8. python基础之虚拟环境--常用指令

    虚拟环境的介绍和应用就不在这里赘述了,做个快捷的记录 这是官方给出来的解释了https://docs.python.org/zh-cn/3.7/tutorial/venv.html 还看到有的人,还安 ...

  9. 杂记-python

    1.在cmd输入python -V显示当前python的版本信息,一定是大写的V 2.输入python,进入python解释器里面 3.在解释器中,输入exit()或者quit()会退出,一定要加括号 ...

  10. SQL查询【根据生日计算】

    根据生日日期,获取当前年龄.年龄单位. Select Case when DateDiff(Year, BirthDate, GetDate()) > 0 then DateDiff(Year, ...