• 【BZOJ】2648: SJY摆棋子 & 2716: [Violet 3]天使玩偶(kdtree)


    http://www.lydsy.com/JudgeOnline/problem.php?id=2716

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

    双倍经验题。。。

    kdtree裸题吧。。。。。今天学了下kdtree。。。感觉挺简单的。。。。

    其实就是对几何图形进行剖分建树,而特殊在于,x和y轴轮流剖。。。。这样可以提供很好的性质以便于查找。。。

    (一开始脑补了个treap代替kdtree。。。。。显然我脑残了。。。。写到一半发现这是不能旋转的。。。。。

    (然后又脑补了下。。。。这货如果和孙子(儿子的儿子)可以旋转。。。。。。。。因为这货的节点类似红黑树。。。但是蒟蒻我太弱从来没写过红黑树。。。

    很好的资料(概念脑补):http://www.cnblogs.com/v-July-v/archive/2012/11/20/3125419.html

    一些参考代码(虽然说完全没按照这样写):http://blog.csdn.net/jiangshibiao/article/details/34144829

    说一下怎么查找。

    首先这是曼哈顿距离。。和欧几里得距离不同。。。如果欧几里得那么简单多了。。

    我们需要维护极值(即能包围所有子树包括自己的点的一个矩形的四个顶点):

    如果要查找的点在矩形内,那么进入查找。

    如果在矩形外,那么计算出查找点到矩形的曼哈顿距离,判断是否小于当前最优解,如果是,进入搜索。

    (或许还能优化,因为一开始我的想法和这个不怎么一样。。我觉得。。递归进入两棵子树中其中一棵后(按x或y排序而不是找极值),然后判断最优解是否能从左子树的某个点越过当前根的分割线。。。。。如果是,就进入。。。

    然后就没了。。。

    留下的坑:欧几里得的没写过。。。删除操作没写过(觉对要斯巴达。。。。想写成平衡树(强迫症系列

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <map>
    using namespace std;
    typedef long long ll;
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << (#x) << " = " << (x) << endl
    #define error(x) (!(x)?puts("error"):0)
    #define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    
    const int N=2000005, oo=~0u>>1;
    struct node *null;
    struct node {
    	node *c[2];
    	int mx[2], mn[2], p[2];
    	void upd(node *x) {
    		if(x==null) return;
    		mx[0]=max(mx[0], x->mx[0]);
    		mx[1]=max(mx[1], x->mx[1]);
    		mn[0]=min(mn[0], x->mn[0]);
    		mn[1]=min(mn[1], x->mn[1]);
    	}
    	int getdis(node *x) {
    		int ret=0;
    		ret+=max(x->p[0]-mx[0], 0);
    		ret+=max(x->p[1]-mx[1], 0);
    		ret+=max(mn[0]-x->p[0], 0);
    		ret+=max(mn[1]-x->p[1], 0);
    		return ret;
    	}
    	void init(int x, int y) {
    		p[0]=mx[0]=mn[0]=x;
    		p[1]=mx[1]=mn[1]=y;
    		c[0]=c[1]=null;
    	}
    	int dis(node *x) { return abs(p[0]-x->p[0])+abs(p[1]-x->p[1]); }
    }*root, T[N], *Tcnt=T;
    node *newnode(int x=0, int y=0) { Tcnt->init(x, y); return Tcnt++; }
    void init() { null=newnode(); null->c[0]=null->c[1]=null; root=null; }
    void insert(node *&x, node *y, bool f) {
    	if(x==null) { x=y; return; }
    	bool d=x->p[f]<y->p[f];
    	x->upd(y);
    	insert(x->c[d], y, !f);
    }
    void ins(int x, int y) { insert(root, newnode(x, y), 0); }
    void ask(node *x, node *y, int &ans) {
    	ans=min(ans, x->dis(y));
    	int d[2];
    	d[0]=x->c[0]==null?oo:x->c[0]->getdis(y);
    	d[1]=x->c[1]==null?oo:x->c[1]->getdis(y);
    	bool f=d[0]>d[1]; if(d[f]==oo) return;
    	ask(x->c[f], y, ans); if(d[!f]<ans) ask(x->c[!f], y, ans);
    }
    int ask(int x, int y) {
    	int ret=oo; static node r;
    	r.p[0]=x; r.p[1]=y;
    	ask(root, &r, ret);
    	return ret;
    }
    int main() {
    	init();
    	int n=getint(), m=getint();
    	rep(i, n) { int x=getint(), y=getint(); ins(x, y); }
    	while(m--) {
    		int t=getint(), x=getint(), y=getint();
    		if(t==2) printf("%d
    ", ask(x, y));
    		else ins(x, y);
    	}
    	return 0;
    }
    

      


    Description

    这天,SJY显得无聊。在家自己玩。在一个棋盘上,有N个黑色棋子。他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子。此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) 。现在给出N<=500000个初始棋子。和M<=500000个操作。对于每个白色棋子,输出距离这个白色棋子最近的黑色棋子的距离。同一个格子可能有多个棋子。
     

    Input

    第一行两个数 N M
    以后M行,每行3个数 t x y
    如果t=1 那么放下一个黑色棋子
    如果t=2 那么放下一个白色棋子

    Output

    对于每个T=2 输出一个最小距离
     

    Sample Input

    2 3
    1 1
    2 3
    2 1 2
    1 3 3
    2 4 2

    Sample Output


    1
    2

    HINT

     

    kdtree可以过

    Source

  • 相关阅读:
    碰撞检测 :Polygon
    碰撞检测 :Line
    碰撞检测 :Rectangle
    碰撞检测:Point
    Canvas 绘制 1 px 直线模糊(非高清屏)的问题
    threading之线程的开始,暂停和退出
    win10利用hexo+gitee搭建博客
    Fullscreen API与DOM监听API
    <el-input>只能输入数字,保留两位小数
    谷歌浏览器查看gitee和github代码的插件
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4166158.html
Copyright © 2020-2023  润新知