KD-Tree复习笔记(BZOJ1941 & BZOJ2648 & BZOJ4066)
快一年了都没碰到什么必须用KDT的题目导致模板完全忘光了,重新复习了一下。
K_Dimention_Tree是一种用来处理二维以上问题的数据结构(OI中一般都是二维),本质是二维启发式估价函数实现剪枝(实际上就是暴搜的优化),随机数据是大常数$O(n\log n)$,构造数据是$O(n\sqrt{n})$,但是好像可以过50W。
先说一下实现:
Build() : 对于二维中的一系列点,枚举x坐标中位数的一条直线,直线两边的点分别划为左右子树,下一层枚举y坐标中位数,不断交替进行。
Ins() : 同样x,y坐标交替作为关键字插入,类似平衡数,代码很简短。
Que() : 先求出两棵子树的估价函数,选估价更优的递归下去,然后递归另一个(如果估价比当前答案还要劣则剪枝)。由此可知,估价函数和A-Star中的启发式函数一样,必须保证估价比实际优。
下面分别说一下两个模型的启发式函数:
1.曼哈顿最小值和最大值:
int getmn(P a){ int s=; rep(i,,) s+=max(T[i]-a.mx[i],),s+=max(a.mn[i]-T[i],); return s; }
int getmx(P a){ int s=; rep(i,,) s+=max(abs(T[i]-a.mx[i]),abs(T[i]-a.mn[i])); return s; }
2.欧氏距离最大值:
int getmx(P a){ int s=; rep(i,,) s+=sqr(max(abs(T[i]-a.mx[i]),abs(T[i]-a.mn[i]))); return s; }
几个注意点:
1.并不一定需要启发式函数,只需要普通的显然的剪枝,KD树也不一定是求最优化,见下面例题。
2.模板稍长且很容易写错,并且很多时候出错不体现在WA而是TLE,写的时候一定要注意细节。
3.build因为有时是rebuild,所以没有数的地方要返回0(被坑了好多次)
下面是例题:
1. BZOJ1941
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const int N=,inf=;
int n,ans=inf,res,rt,F=; inline void cmin(int &x,int y){ if (y<x) x=y; }
inline void cmax(int &x,int y){ if (y>x) x=y; }
int abs(int x){ return (x<) ? -x : x; } struct P{
int d[],mx[],mn[],l,r;
int& operator [](int x){ return d[x]; }
friend bool operator <(P a,P b){ return a[F]<b[F]; }
friend int dis(P a,P b){ return abs(a[]-b[])+abs(a[]-b[]); }
}p[N],t[N],T; void upd(int x){
int l=t[x].l,r=t[x].r;
rep(i,,){
t[x].mn[i]=t[x].mx[i]=t[x][i];
if (l) cmin(t[x].mn[i],t[l].mn[i]),cmax(t[x].mx[i],t[l].mx[i]);
if (r) cmin(t[x].mn[i],t[r].mn[i]),cmax(t[x].mx[i],t[r].mx[i]);
}
} int build(int l,int r,int k){
if (l>r) return ;
F=k; int mid=(l+r)>>;
nth_element(p+l,p+mid,p+r+); t[mid]=p[mid];
rep(i,,) t[mid].mn[i]=t[mid].mx[i]=t[mid][i];
t[mid].l=build(l,mid-,k^); t[mid].r=build(mid+,r,k^);
upd(mid); return mid;
} int getmn(P a){ int s=; rep(i,,) s+=max(T[i]-a.mx[i],),s+=max(a.mn[i]-T[i],); return s; }
int getmx(P a){ int s=; rep(i,,) s+=max(abs(T[i]-a.mx[i]),abs(T[i]-a.mn[i])); return s; } void quemn(int x){
int tmp=dis(T,t[x]);
if (tmp) res=min(res,tmp);
int l=t[x].l,r=t[x].r,dl=inf,dr=inf;
if (l) dl=getmn(t[l]); if (r) dr=getmn(t[r]);
if (dl<dr) { if (dl<res) quemn(l); if (dr<res) quemn(r); }
else { if (dr<res) quemn(r); if (dl<res) quemn(l); }
} void quemx(int x){
res=max(res,dis(T,t[x]));
int l=t[x].l,r=t[x].r,dl=-inf,dr=-inf;
if (l) dl=getmx(t[l]); if (r) dr=getmx(t[r]);
if (dl>dr) { if (dl>res) quemx(l); if (dr>res) quemx(r); }
else { if (dr>res) quemx(r); if (dl>res) quemx(l); }
} int que(int f,int x,int y){
T[]=x; T[]=y;
if (f) res=-inf,quemx(rt); else res=inf,quemn(rt);
return res;
} int main(){
freopen("bzoj1941.in","r",stdin);
freopen("bzoj1941.out","w",stdout);
scanf("%d",&n);
rep(i,,n) scanf("%d%d",&p[i][],&p[i][]);
rt=build(,n,);
rep(i,,n) ans=min(ans,que(,p[i][],p[i][])-que(,p[i][],p[i][]));
printf("%d\n",ans);
return ;
}
2.BZOJ2648
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const int N=,inf=;
int n,m,F,nd,rt,op,res; inline void cmin(int &x,int y){ if (y<x) x=y; }
inline void cmax(int &x,int y){ if (y>x) x=y; }
int abs(int x){ return (x<) ? -x : x; } struct P{
int d[],mn[],mx[],l,r;
int& operator [](int x){ return d[x]; }
friend bool operator <(P a,P b){ return a[F]<b[F]; }
friend int dis(P a,P b){ return abs(a[]-b[])+abs(a[]-b[]); }
}p[N],t[N],a; void upd(int x){
int l=t[x].l,r=t[x].r;
rep(i,,){
t[x].mn[i]=t[x].mx[i]=t[x][i];
if (l) cmin(t[x].mn[i],t[l].mn[i]),cmax(t[x].mx[i],t[l].mx[i]);
if (r) cmin(t[x].mn[i],t[r].mn[i]),cmax(t[x].mx[i],t[r].mx[i]);
}
} int build(int l,int r,int k){
if (l>r) return ;
F=k; int mid=(l+r)>>;
nth_element(p+l,p+mid,p+r+); t[mid]=p[mid];
rep(i,,) t[mid].mn[i]=t[mid].mx[i]=t[mid][i];
t[mid].l=build(l,mid-,k^); t[mid].r=build(mid+,r,k^);
upd(mid); return mid;
} void ins(int &x,int k){
if (!x) { t[x=++nd]=a; upd(x); return; }
if (a[k]<=t[x][k]) ins(t[x].l,k^); else ins(t[x].r,k^);
upd(x);
} int get(int x){
int s=;
rep(i,,) s+=max(a[i]-t[x].mx[i],)+max(t[x].mn[i]-a[i],);
return s;
} void que(int x){
res=min(res,dis(t[x],a));
int l=t[x].l,r=t[x].r,dl=inf,dr=inf;
if (l) dl=get(l); if (r) dr=get(r);
if (dl<dr) { if (dl<res) que(l); if (dr<res) que(r); }
else { if (dr<res) que(r); if (dl<res) que(l); }
} int main(){
scanf("%d%d",&n,&m);
rep(i,,n) scanf("%d%d",&p[i][],&p[i][]);
rt=build(,n,); nd=n;
rep(i,,m){
scanf("%d%d%d",&op,&a[],&a[]);
if (op==) ins(rt,); else res=inf,que(rt),printf("%d\n",res);
}
return ;
}
3.BZOJ4066
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
#define G x1,y1,x2,y2,t[x].mn[0],t[x].mn[1],t[x].mx[0],t[x].mx[1]
typedef long long ll;
using namespace std; const int N=;
int n,op,F,rt,m=;
ll v,ans,cnt,x1,y1,x2,y2; inline void cmin(int &x,int y){ if (y<x) x=y; }
inline void cmax(int &x,int y){ if (y>x) x=y; } bool in(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2)
{ return x1<=X1 && X2<=x2 && y1<=Y1 && Y2<=y2;}
bool out(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2)
{ return x1>X2 || x2<X1 || y1>Y2 || y2<Y1; } struct P{
int d[],mn[],mx[],l,r,v; ll sm;
int& operator [](int x){ return d[x]; }
friend bool operator <(P a,P b){ return a[F]<b[F]; }
}T,p[N],t[N]; void upd(int x){
int l=t[x].l,r=t[x].r;
rep(i,,){
t[x].mn[i]=t[x].mx[i]=t[x][i];
if (l) cmin(t[x].mn[i],t[l].mn[i]),cmax(t[x].mx[i],t[l].mx[i]);
if (r) cmin(t[x].mn[i],t[r].mn[i]),cmax(t[x].mx[i],t[r].mx[i]);
}
t[x].sm=t[l].sm+t[r].sm+t[x].v;
} int build(int l,int r,int k){
if (l>r) return ;
F=k; int mid=(l+r)>>;
nth_element(p+l,p+mid,p+r+); t[mid]=p[mid];
t[mid].l=build(l,mid-,k^); t[mid].r=build(mid+,r,k^);
upd(mid); return mid;
} void ins(int &x,int k){
if (!x) { t[x=++cnt]=T; upd(x); return; }
if (T[]==t[x][] && T[]==t[x][]){ t[x].v+=T.v; t[x].sm+=T.v; return; }
if (T[k]<t[x][k]) ins(t[x].l,k^); else ins(t[x].r,k^);
upd(x);
} ll que(int x,int x1,int y1,int x2,int y2){
if (!x) return ; ll tmp=,l=t[x].l,r=t[x].r;
if (in(G)) return t[x].sm; if (out(G)) return ;
if (in(x1,y1,x2,y2,t[x][],t[x][],t[x][],t[x][])) tmp+=t[x].v;
tmp+=que(l,x1,y1,x2,y2)+que(r,x1,y1,x2,y2);
return tmp;
} int main(){
freopen("bzoj4066.in","r",stdin);
freopen("bzoj4066.out","w",stdout);
scanf("%d",&n);
while (){
scanf("%d",&op);
if (op==) break;
if (op==){
scanf("%lld%lld%lld",&x1,&y1,&v);
T[]=x1^ans; T[]=y1^ans; T.v=v^ans; ins(rt,);
if (cnt==m){
rep(i,,cnt) p[i]=t[i]; m+=; rt=build(,cnt,);
}
}else{
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
x1^=ans; y1^=ans; x2^=ans; y2^=ans;
printf("%lld\n",ans=que(rt,x1,y1,x2,y2));
}
}
return ;
}
4.崂山百花蛇草水:见LOJ代码
KD-Tree复习笔记(BZOJ1941 & BZOJ2648 & BZOJ4066)的更多相关文章
- k-d tree 学习笔记
以下是一些奇怪的链接有兴趣的可以看看: https://blog.sengxian.com/algorithms/k-dimensional-tree http://zgjkt.blog.uoj.ac ...
- K-D Tree学习笔记
用途 做各种二维三维四维偏序等等. 代替空间巨大的树套树. 数据较弱的时候水分. 思想 我们发现平衡树这种东西功能强大,然而只能做一维上的询问修改,显得美中不足. 于是我们尝试用平衡树的这种二叉树结构 ...
- kd tree学习笔记 (最近邻域查询)
https://zhuanlan.zhihu.com/p/22557068 http://blog.csdn.net/zhjchengfeng5/article/details/7855241 KD树 ...
- 【BZOJ-2648&2716】SJY摆棋子&天使玩偶 KD Tree
2648: SJY摆棋子 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2459 Solved: 834[Submit][Status][Discu ...
- [学习笔记]K-D Tree
以前其实学过的但是不会拍扁重构--所以这几天学了一下 \(K-D\ Tree\) 的正确打开姿势. \(K\) 维 \(K-D\ Tree\) 的单次操作最坏时间复杂度为 \(O(k\times n^ ...
- BZOJ1941:[SDOI2010]Hide and Seek(K-D Tree)
Description 小猪iPig在PKU刚上完了无聊的猪性代数课,天资聪慧的iPig被这门对他来说无比简单的课弄得非常寂寞,为了消除寂寞感,他决定和他的好朋友giPi(鸡皮)玩一个更加寂寞的游戏- ...
- BZOJ4066:简单题(K-D Tree)
Description 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 ...
- BZOJ2648/2716:SJY摆棋子/[Violet]天使玩偶(K-D Tree)
Description 这天,SJY显得无聊.在家自己玩.在一个棋盘上,有N个黑色棋子.他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子. ...
- luogu4169 [Violet]天使玩偶/SJY摆棋子 / bzoj2648 SJY摆棋子 k-d tree
k-d tree + 重构的思想,就能卡过luogu和bzoj啦orz #include <algorithm> #include <iostream> #include &l ...
随机推荐
- Cannot create a secure XMLInputFactory --CXF调用出错
在调用方法前加上下面三句即可调用成功: Properties props = System.getProperties(); props.setProperty("org.apache.cx ...
- Oracle 监听/数据库 启动/关闭
LSNRCTL命令启动.关闭和查看监听器的状态的方法 从lsnrctl status命令的输出中得到监听器状态,包括如下的信息: 监听器的启动时间 监听器的运行时间 监听器参数文件listener.o ...
- 游戏开发学习ing
创建工程 python cocos.py new HelloWorld -p com.cocos2dx.org -l cpp -d myprojects 这个命令就是运行python然后编译cos.p ...
- 史林枫:开源HtmlAgilityPack公共小类库封装 - 网页采集(爬虫)辅助解析利器【附源码+可视化工具推荐】
做开发的,可能都做过信息采集相关的程序,史林枫也经常做一些数据采集或某些网站的业务办理自动化操作软件. 获取目标网页的信息很简单,使用网络编程,利用HttpWebResponse.HttpWebReq ...
- InnoDB 存储引擎的线程与内存池
InnoDB 存储引擎的线程与内存池 InnoDB体系结构如下: 后台线程: 1.后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据: 2.另外,将以修改的数据文件刷 ...
- [洛谷P2216][HAOI2007]理想的正方形
题目大意:有一个$a\times b$的矩阵,求一个$n\times n$的矩阵,使该区域中的极差最小. 题解:二维$ST$表,每一个点试一下是不是左上角就行了 卡点:1.用了一份考试时候写的二维$S ...
- 开头什么的肯定要自我介绍然后把它扔到置顶咯>_<~
大家嚎,我是NanoApe~ 现在高一,是个OIer.音游狗和一个爱着二次元的萌汉子妹子,欢迎前来勾搭>_<~ 最近就是要冲省队啦~~~~加油! 扣扣号:879006461 Weibo:伪 ...
- [poj] 1066 Treasure Hunt || 判断直线相交
原题 在金字塔内有一个宝藏p(x,y),现在要取出这个宝藏. 在金字塔内有许多墙,为了进入宝藏所在的房间必须把墙炸开,但是炸墙只能炸每个房间墙的中点. 求将宝藏运出城堡所需要的最小炸墙数. 判断点和直 ...
- 2013 ACMICPC 杭州现场赛 I题
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #in ...
- windows 下 mySQL 镜像安装文件下载
前言:有时找到的 MySQL 安装文件是 zip 格式的,需要自己配置,自我感觉麻烦,因此记录下下载镜像安装文件过程. 1. 在浏览器里打开mysql的官网http://www.mysql.c ...