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 ...
随机推荐
- 解决ubuntu发热严重的问题
对于双显卡PC安装ubuntu ,风扇狂转,发热严重,原因基本双显卡的优化导致. 解决具体步骤如下: 命令行输入sudo apt-get install bumblebee bumblebee-nvi ...
- kafak基本操作
创建topic bin/kafka-topics.sh --create --zookeeper 192.168.1.81:2181 --replication-factor 3 -partition ...
- 点击图片改变背景的demo-学习第二天
实例代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...
- POJ -1679(次小生成树)模板
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions:34617 Accepted: 12637 D ...
- AGC019-E Shuffle and Swap
给定两个长度为\(n\le 10^5\)的\(01\)串 \(A, B\), 满足 \(1\) 的数量相等 求通过下列方式将\(A\)变成\(B\)的概率 (mod意义下) 构造序列\(a,b\). ...
- 自定义View基础 (1)
前言 自定义View原理是Android开发者必须了解的基础: 在了解自定义View之前,你需要有一定的知识储备: 本文将全面解析关于自定义View中的所有知识基础. 目录 目录 1. View的分类 ...
- python Error Message: command 'gcc' failed with exit status 1
参考:[ CSDN ] 解决方法 yum install gcc libffi-devel python-devel openssl-devel
- 关于try-catch-finally return 的面试题
public class Test { public static void main(String[] args) { System.out.println(test()); } static in ...
- HDU1536&&POJ2960 S-Nim(SG函数博弈)
S-Nim Time Limit: 2000MS Memory Limit: 65536KB 64bit IO Format: %I64d & %I64u Submit Status ...
- CSS技巧----DIV+CSS规范命名大全集合
网页制作中规范使用DIV+CSS命名规则,可以改善优化功效特别是团队合作时候可以提供合作制作效率,具体DIV CSS命名规则CSS命名大全内容篇. 常用DIV+CSS命名大全集合,即CSS命名规则 D ...