HDU ACM 2966 In case of failure ->K_D树模版题

分析:k_d树的模版题,参考了别人的写的;划分的时候采用坐标跨度作为分割依据的效率略比采用树的深度作为划分依据的高;nth_element函数比sort函数的效率高;全部采用getchar和putchar效率也能提高一些。

#include<iostream>
#include<algorithm>
using namespace std;

struct POINT
{
	int x,y;
};

struct K_D_Node
{
	POINT mid;              //分割中点
	int split_axis;         //分割的轴,0为x轴,1为y轴
	K_D_Node* child[2];     //0左子节点,1右子节点
};

#define N 100100
const __int64 inf=0x7fffffffffffffff;
POINT p[N],p2[N];
K_D_Node K_D_Tree[N];
int len;
__int64 ans;

bool cmpx(const POINT& a,const POINT& b)
{
	return a.x<b.x;
}

bool cmpy(const POINT& a,const POINT& b)
{
	return a.y<b.y;
}

K_D_Node* MallocNode()
{
	K_D_Tree[len].child[0]=K_D_Tree[len].child[1]=NULL;
	return &K_D_Tree[len++];
}

K_D_Node* Build_Tree(int L,int R,int depth)
{
	int mid,t;
	K_D_Node* q;
	int minx,miny,maxx,maxy;

	if(L>R) return NULL;
	q=MallocNode();

	//----------------------
	//t=depth%2;               //用树的深度作为分割依据
	//---------------------

	minx=min_element(p+L,p+R,cmpx)->x;          //用坐标跨度作为划分依据
	miny=min_element(p+L,p+R,cmpy)->y;
	maxx=max_element(p+L,p+R,cmpx)->x;
	maxy=max_element(p+L,p+R,cmpy)->y;

	if(maxx-minx>=maxy-miny)
		t=0;
	else
		t=1;

	q->split_axis=t;
	if(L==R)
	{
		q->mid=p[L];
		return q;
	}

	mid=(L+R)>>1;
	if(t==0)                   //以x轴分割
		nth_element(p+L,p+mid,p+R+1,cmpx);
	//	sort(p+L,p+R+1,cmpx);
	else
		nth_element(p+L,p+mid,p+R+1,cmpy);
	//	sort(p+L,p+R+1,cmpy);

	q->mid=p[mid];
	q->child[0]=Build_Tree(L,mid-1,depth+1);   //构建左子树
	q->child[1]=Build_Tree(mid+1,R,depth+1);
	return q;
}

__int64 DIS(const POINT& a,const POINT& b)
{
	__int64 xx,yy;

	xx=a.x-b.x;
	yy=a.y-b.y;
	return (__int64)xx*xx+(__int64)yy*yy;
}

void Query(K_D_Node* q,const POINT& a)
{
	int tmp,s;
	__int64 dis;     //距离平方

	if(q==NULL) return ;

	if(q->split_axis==0)     //X轴
	{
		tmp=q->mid.x;
		s=a.x;
	}
	else                     //Y轴
	{
		tmp=q->mid.y;
		s=a.y;
	}
	if(s<=tmp)
		Query(q->child[0],a);  //左子树
	else
		Query(q->child[1],a);

	dis=DIS(q->mid,a);
	if(dis && dis<ans)//注意这里必须要是dis不等于0才更新,避免处理到自身点,如果输入中有重复点则不能处理
		ans=dis;

	if((__int64)(tmp-s)*(tmp-s)<ans)  //可能在另一半中,查找另一半
	{
		if(s<=tmp)
			Query(q->child[1],a);
		else
			Query(q->child[0],a);
	}
}

int ReadInt()
{
    int ans;
    char c;  

    c=getchar();
    while(c<'0' || c>'9') c=getchar();  

    ans=c-'0';
    while((c=getchar())>='0' && c<='9')
    {
        ans=ans*10+c-'0';
    }
    return ans;
}

void PutInt64(__int64 x)
{
    int b[32],i;  

    i=0;
    while(x)
    {
        b[i++]=x%10;
        x/=10;
    }
    for(i--;i>=0;i--)
        putchar(b[i]+'0');
}

int main()
{
	int t,n,i;
	K_D_Node* root;

	t=ReadInt();
	while(t--)
	{
		n=ReadInt();
		for(i=0;i<n;i++)
		{
			p[i].x=ReadInt();
			p[i].y=ReadInt();
			p2[i]=p[i];
		}

		len=0;
		root=Build_Tree(0,n-1,0);   //建立k_d树
		for(i=0;i<n;i++)
		{
			ans=inf;
			Query(root,p2[i]);
			PutInt64(ans);
			putchar('\n');
		}
	}
    return 0;
}
时间: 2024-07-31 15:29:41

HDU ACM 2966 In case of failure ->K_D树模版题的相关文章

hdu 2966 In case of failure(KD-tree)

题目链接:hdu 2966 In case of failure 题意: 给你n个点,让你输出每个点到最近点的欧式距离. 题解: KD-树裸题,板子抄的鸟神的. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=(a);i<=(b);++i) 3 using namespace std; 4 using ll=long long; 5 6 namespace KD_Tree{ 7 const int N=1e5+7,DI=2;

hdu acm 1166 敌兵布阵 (线段树)

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 37903    Accepted Submission(s): 15985 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

HDU 4027 Can you answer these queries? 线段树裸题

题意: 给定2个操作 0.把区间的每个数sqrt 2.求和 因为每个数的sqrt次数很少,所以直接更新到底,用个标记表示是否更新完全(即区间内的数字只有0,1就不用再更新了) #include<stdio.h> #include<iostream> #include<algorithm> #include<vector> #include<cmath> #include<queue> #include<set> #incl

[HDU 2966]In case of failure

Description To help their clients deal with faulty Cash Machines, the board of The Planar Bank has decided to stick a label expressing sincere regret and sorrow of the bank about the failure on every ATM. The very same label would gently ask the cust

hdu 2966 In case of failure kdtree模板题

问求每个点距离平方的最小的点 kd-tree模板题…… 1 #include<bits/stdc++.h> 2 #define cl(a,b) memset(a,b,sizeof(a)) 3 #define debug(x) cerr<<#x<<"=="<<(x)<<endl 4 using namespace std; 5 typedef long long ll; 6 typedef pair<int,int>

杭电 HDU ACM 1698 Just a Hook(线段树 区间更新 延迟标记)

欢迎"热爱编程"的高考少年--报考杭州电子科技大学计算机学院 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 20889    Accepted Submission(s): 10445 Problem Description In the game of DotA, Pudge's meat hook

HDU ACM 5214 Movie -&gt;贪心+自然溢出取模-&gt;水题里的学问

分析:贪心,首先找到最右边的第一个左边界和最左边的第一个右边界.之后在判断是否有一个及一个以上的区间在这两个值之间,若有则能找到符合题意的三个区间,否则不能. 注意:这里利用的unsigned int的自然溢出决解了取模问题:第二个是一定生成完数据后在交换Li和Ri的值,这里被坑残了. #include<iostream> using namespace std; //__int64 mod=4294967296;由于4294967296-1刚好是unsigned int类型的最大值,对它取模

杭电 HDU ACM 1754 I Hate It (线段树)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 47272    Accepted Submission(s): 18507 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师

HDU ACM 4006 The kth great number 线段树?优先队列?

分析:可以用线段树做,但感觉麻烦.用优先队列,每次插入时都保留前k个大的数即可. #include<iostream> #include<functional> #include<queue> using namespace std; int main() { int n,k,j,c; char b[2]; ios::sync_with_stdio(false); while(cin>>n>>k) { priority_queue<int,