kd-tree小结

来省队集训被吊打,于是无聊学了一下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
#include
#include
#include
#include
#include
#define maxn 500010
#define inf 1000000000

using 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]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


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

这才是真正的kdtree模板,带上一个插入操作,类似平衡树的思想。

#include
#include
#include
#include
#include
#include
#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]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=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 
#include 
#include 
#include 
#include 
#include 
#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]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; 
} 


你可能感兴趣的:(总结,数据结构)