快一年了都没碰到什么必须用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)的更多相关文章

  1. k-d tree 学习笔记

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

  2. K-D Tree学习笔记

    用途 做各种二维三维四维偏序等等. 代替空间巨大的树套树. 数据较弱的时候水分. 思想 我们发现平衡树这种东西功能强大,然而只能做一维上的询问修改,显得美中不足. 于是我们尝试用平衡树的这种二叉树结构 ...

  3. kd tree学习笔记 (最近邻域查询)

    https://zhuanlan.zhihu.com/p/22557068 http://blog.csdn.net/zhjchengfeng5/article/details/7855241 KD树 ...

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

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

  5. [学习笔记]K-D Tree

    以前其实学过的但是不会拍扁重构--所以这几天学了一下 \(K-D\ Tree\) 的正确打开姿势. \(K\) 维 \(K-D\ Tree\) 的单次操作最坏时间复杂度为 \(O(k\times n^ ...

  6. BZOJ1941:[SDOI2010]Hide and Seek(K-D Tree)

    Description 小猪iPig在PKU刚上完了无聊的猪性代数课,天资聪慧的iPig被这门对他来说无比简单的课弄得非常寂寞,为了消除寂寞感,他决定和他的好朋友giPi(鸡皮)玩一个更加寂寞的游戏- ...

  7. BZOJ4066:简单题(K-D Tree)

    Description 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:   命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 ...

  8. BZOJ2648/2716:SJY摆棋子/[Violet]天使玩偶(K-D Tree)

    Description 这天,SJY显得无聊.在家自己玩.在一个棋盘上,有N个黑色棋子.他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子. ...

  9. luogu4169 [Violet]天使玩偶/SJY摆棋子 / bzoj2648 SJY摆棋子 k-d tree

    k-d tree + 重构的思想,就能卡过luogu和bzoj啦orz #include <algorithm> #include <iostream> #include &l ...

随机推荐

  1. 云效(阿里云)流水线 + nginx + uWsgi + flask + python3 基础环境搭建 --备忘

    一.开发环境搭建 1.安装python3 yum -y groupinstall "Development tools" yum -y install zlib-devel bzi ...

  2. poj 2299 归并排序求逆序数 (可做模板)

    Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 48077   Accepted: 17533 Description In ...

  3. SQLServer对视图或函数’XXX’的更新或插入失败,因其包含派生域或常量域解决

    原因:视图view不允许修改. 解决:重新创建一个相同结构内容的表. 解释:因为所创建的视图对其属性值进行了计算的其他形式上的改变,而对视图的更改最终表现为对表的更改而表中不存在视图的某一属性,或属性 ...

  4. easyui中tab页中js脚本无法加载的问题及解决方法

    我发现tab页中<script src="xxx.js">方式加载的脚本没有生效,firebug看请求也没有请求相应的脚本文件. 单独在浏览器中打开tab页中的页面js ...

  5. [poj] 1269 [zoj] 1280 Interesting Lines || 求两直线交点

    POJ原题 ZOJ原题 多组数据.每次给出四个点,前两个点确定一条直线,后两个点确定一条直线,若平行则输出"NONE",重合输出"LINE",相交输出" ...

  6. 虚拟机——mnt_hgfs下无目录情况解决

    /mnt/hgfs下无目录情况解决: VMware8虚拟机安装Ubuntu 11.10使用share folders共享目录将虚拟机掉电关闭(不能暂停),设置share folders目录,重启虚拟机 ...

  7. chrome性能指标(TTFB,TTSR,TTDC,TTFL)

    1.TTFB (Time To First Byte) 是最初的网络请求被发起到从服务器接收到第一个字节这段时间,它包含了 TCP连接时间,发送HTTP请求时间和获得响应消息第一个字节的时间. 注意: ...

  8. Jquery不同版本共用的解决方案(插件编写)

    最近在为某公司做企业内部UI库,经过研究分析和评审,决定基于Jquery开发,结合Bootstrap插件那简洁,优雅,高效的思想进行插件编写. 但是在编写的过程中遇到一个头疼的问题,就是正在编写的插件 ...

  9. Codeforces Round #516 (Div. 2)D. Labyrinth

    D. Labyrinth 题目链接:https://codeforces.com/contest/1064/problem/D 题意: 给出一个n*m的矩阵以及人物的起点,并且给出x,y,分别代表这个 ...

  10. Jquery CheckBox 选中和非选中

    if($("input[name='is_pay']").prop('checked')) { $("input[name='is_pay']").prop(' ...