kd-tree小结
来源:互联网 发布:华为荣耀4停用移动数据 编辑:程序博客网 时间:2024/04/29 02:48
来省队集训被吊打,于是无聊学了一下kd-tree,挺好玩的东西。
kd-tree是一种支持查询平面最近点(其实是k维,但这种题目比较少)的数据结构,单次理论时间复杂度O(√n),但实际是非常快的,可以说kd-tree就是一种比较优化的暴力。
kd-tree的思想是将平面进行分割,第一次按第一维分割,第二次按第二维分割,然后接着按第一维分割,直至每个叶子节点只包含一个点,类似线段树的结构。查询时,先查询到叶子节点,然后通过回溯,对于每一个节点算出,最小的可能距离,如果小于当前的ans,就向下查询。同样,kd-tree也可以建成平衡树的模式,这样的优势是可以插入节点。
模板:
bzoj1941 http://www.lydsy.com/JudgeOnline/problem.php?id=1941
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#define maxn 500010#define inf 1000000000using namespace std;int n,m,cur,ans,root;int x[maxn],y[maxn];struct P{int mn[2],mx[2],d[2],lch,rch;int& operator[](int x) {return d[x];}friend bool operator<(P x,P y) {return x[cur]<y[cur];}friend int dis(P x,P y) {return abs(x[0]-y[0])+abs(x[1]-y[1]);}}p[maxn];struct kdtree{P t[maxn],T;int ans;void update(int k){int l=t[k].lch,r=t[k].rch;for (int i=0;i<2;i++){t[k].mn[i]=t[k].mx[i]=t[k][i];if (l) t[k].mn[i]=min(t[k].mn[i],t[l].mn[i]);if (r) t[k].mn[i]=min(t[k].mn[i],t[r].mn[i]);if (l) t[k].mx[i]=max(t[k].mx[i],t[l].mx[i]);if (r) t[k].mx[i]=max(t[k].mx[i],t[r].mx[i]); }}int build(int l,int r,int now){cur=now;int mid=(l+r)/2;nth_element(p+l,p+mid,p+r+1);t[mid]=p[mid];for (int i=0;i<2;i++) t[mid].mx[i]=t[mid].mn[i]=t[mid][i];if (l<mid) t[mid].lch=build(l,mid-1,now^1);if (r>mid) t[mid].rch=build(mid+1,r,now^1);update(mid);return mid;}int getmn(P x){int ans=0;for (int i=0;i<2;i++){ans+=max(T[i]-x.mx[i],0);ans+=max(x.mn[i]-T[i],0);}return ans;}int getmx(P x){int ans=0;for (int i=0;i<2;i++) ans+=max(abs(T[i]-x.mn[i]),abs(T[i]-x.mx[i]));return ans;}void querymx(int k){ans=max(ans,dis(t[k],T));int l=t[k].lch,r=t[k].rch,dl=-inf,dr=-inf;if (l) dl=getmx(t[l]);if (r) dr=getmx(t[r]);if (dl>dr){if (dl>ans) querymx(l);if (dr>ans) querymx(r);}else{if (dr>ans) querymx(r);if (dl>ans) querymx(l);}}void querymn(int k){if (dis(t[k],T)) ans=min(ans,dis(t[k],T));int l=t[k].lch,r=t[k].rch,dl=inf,dr=inf;if (l) dl=getmn(t[l]);if (r) dr=getmn(t[r]);if (dl<dr){if (dl<ans) querymn(l);if (dr<ans) querymn(r);}else{if (dr<ans) querymn(r);if (dl<ans) querymn(l);}}int query(int f,int x,int y){T[0]=x;T[1]=y;if (f==0) ans=-inf,querymx(root);else ans=inf,querymn(root);return ans;}}kdtree;int main(){scanf("%d",&n);for (int i=1;i<=n;i++){scanf("%d%d",&x[i],&y[i]);p[i][0]=x[i];p[i][1]=y[i];}root=kdtree.build(1,n,0);ans=inf;for (int i=1;i<=n;i++){int mx=kdtree.query(0,x[i],y[i]),mn=kdtree.query(1,x[i],y[i]);ans=min(ans,mx-mn);}printf("%d\n",ans);return 0;}
bzoj2716/2648 http://www.lydsy.com/JudgeOnline/problem.php?id=2716
这才是真正的kdtree模板,带上一个插入操作,类似平衡树的思想。
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#define maxn 1000010#define inf 1000000000 using namespace std; int n,m,root,ans,cur; int fabs(int x){ if (x>=0) return x; else return -x;} struct P{ int d[2],mx[2],mn[2],lch,rch; int& operator[](int x) {return d[x];} friend bool operator<(P x,P y) {return x[cur]<y[cur];} friend int dis(P x,P y) {return fabs(x[0]-y[0])+fabs(x[1]-y[1]);}}p[maxn]; struct kdtree{ P t[maxn],T; int ans; void update(int k) { int l=t[k].lch,r=t[k].rch; for (int i=0;i<2;i++) { t[k].mn[i]=t[k].mx[i]=t[k][i]; if (l) t[k].mn[i]=min(t[k].mn[i],t[l].mn[i]); if (r) t[k].mn[i]=min(t[k].mn[i],t[r].mn[i]); if (l) t[k].mx[i]=max(t[k].mx[i],t[l].mx[i]); if (r) t[k].mx[i]=max(t[k].mx[i],t[r].mx[i]); } } int build(int l,int r,int now) { cur=now; int mid=(l+r)/2; nth_element(p+l,p+mid,p+r+1); t[mid]=p[mid]; for (int i=0;i<2;i++) t[mid].mn[i]=t[mid].mx[i]=t[mid][i]; if (l<mid) t[mid].lch=build(l,mid-1,now^1); if (r>mid) t[mid].rch=build(mid+1,r,now^1); update(mid); return mid; } int getmn(P x) { int tmp=0; for (int i=0;i<2;i++) { tmp+=max(T[i]-x.mx[i],0); tmp+=max(x.mn[i]-T[i],0); } return tmp; } void querymn(int k) { ans=min(ans,dis(t[k],T)); int l=t[k].lch,r=t[k].rch,dl=inf,dr=inf; if (l) dl=getmn(t[l]); if (r) dr=getmn(t[r]); if (dl<dr) { if (dl<ans) querymn(l); if (dr<ans) querymn(r); } else { if (dr<ans) querymn(r); if (dl<ans) querymn(l); } } void insert(int k,int now) { if (T[now]>=t[k][now]) { if (t[k].rch) insert(t[k].rch,now^1); else { t[k].rch=++n;t[n]=T; for (int i=0;i<2;i++) t[n].mx[i]=t[n].mn[i]=t[n][i]; } } else { if (t[k].lch) insert(t[k].lch,now^1); else { t[k].lch=++n;t[n]=T; for (int i=0;i<2;i++) t[n].mx[i]=t[n].mn[i]=t[n][i]; } } update(k); } int query(int x,int y) { ans=inf; T[0]=x;T[1]=y;T.lch=0;T.rch=0; querymn(root); return ans; } void insert1(int x,int y) { T[0]=x;T[1]=y;T.lch=0;T.rch=0;insert(root,0); }}kdtree; int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d%d",&p[i][0],&p[i][1]); root=kdtree.build(1,n,0); while (m--) { int op,x,y; scanf("%d%d%d",&op,&x,&y); if (op==1) kdtree.insert1(x,y); else printf("%d\n",kdtree.query(x,y)); } return 0;}
bzoj2850 http://www.lydsy.com/JudgeOnline/problem.php?id=2850
类似模板的算法,只不过换了一下估价函数,将曼哈顿距离换成了ax+by,维护一下子树的权值和来加速。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #define maxn 50010 #define inf 1000000000 using namespace std; int n,m,root,cur;long long a,b,c; long long ans; struct P { int d[2],mx[2],mn[2],lch,rch,key; long long sum; int& operator[](int x) {return d[x];} friend bool operator<(P a,P b) {return a[cur]<b[cur];} }p[maxn]; int check(long long x,long long y) { return (long long)a*x+b*y<c; } int cal(P a) { int tmp=0; tmp+=check(a.mx[0],a.mx[1]); tmp+=check(a.mx[0],a.mn[1]); tmp+=check(a.mn[0],a.mx[1]); tmp+=check(a.mn[0],a.mn[1]); return tmp;} struct kdtree { P t[maxn]; void update(int k) { int l=t[k].lch,r=t[k].rch; for (int i=0;i<2;i++) { t[k].mn[i]=t[k].mx[i]=t[k][i]; if (l) t[k].mn[i]=min(t[k].mn[i],t[l].mn[i]); if (r) t[k].mn[i]=min(t[k].mn[i],t[r].mn[i]); if (l) t[k].mx[i]=max(t[k].mx[i],t[l].mx[i]); if (r) t[k].mx[i]=max(t[k].mx[i],t[r].mx[i]); } t[k].sum=(long long)t[k].key+t[l].sum+t[r].sum; } int build(int l,int r,int now) { cur=now; int mid=(l+r)/2; nth_element(p+l,p+mid,p+r+1); t[mid]=p[mid]; if (l<mid) t[mid].lch=build(l,mid-1,now^1); if (r>mid) t[mid].rch=build(mid+1,r,now^1); update(mid); return mid; } void query(int k) { if (check(t[k][0],t[k][1])) ans+=t[k].key; int l=t[k].lch,r=t[k].rch,dl=0,dr=0; if (l) dl=cal(t[l]); if (r) dr=cal(t[r]); if (dl==4) ans+=t[l].sum; else if (dl) query(l); if (dr==4) ans+=t[r].sum; else if (dr) query(r); } }kdtree; int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d%d%d",&p[i][0],&p[i][1],&p[i].key); root=kdtree.build(1,n,0); while (m--) { scanf("%lld%lld%lld",&a,&b,&c); ans=0; kdtree.query(root); printf("%lld\n",ans); } return 0; }
0 0
- kd-tree小结
- [BZOJ3489]A simple rmq problem(KD-tree||主席树+KD-tree小结)
- kd-tree
- KD Tree
- KD Tree
- kd-tree
- kd-tree
- kd-tree
- kd tree
- KD-Tree
- Kd-tree
- kd-tree
- kd-tree
- kd-tree
- kd-tree
- kd tree
- kd-tree
- KD Tree
- 图_邻接矩阵_DFS_BFS
- C&C++(3) - 在C与C++中运行结果不同的程序
- Hibernate的持久化对象
- 反向Ajax技术实例(二)
- java面试学习知识点
- kd-tree小结
- 设计手册——216网页安全色大全【附颜色编码对照表】
- 反硬币
- STM32移植uCOS-II系统(1)
- 架构注意事项
- 工厂模式
- C语言函数及多文件团队开发
- DWR框架
- 设计模式中类的关系