题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5809
题解:
KDtree的板题啊,求出每一个点的最近的那个点,然后建立双向边,然后用Tarjan进行缩点,对于每一次查询,判断两个点是否在同一个联通块里就行了。就是代码长了点?没人愿意补这个题吧。。。
#include<bits/stdc++.h>
#define mp Point
using namespace std;
typedef long long ll;
const ll inf=9e18;
const int MAXN=1e5+5;
namespace KD_Tree
{
struct node
{
node *ch[2];
ll d[2],mx[2],my[2];
int id;//d表示这个点的坐标[0]->x,[1]->y,mx表示这个平面的x的范围,my表示这个平面的y的范围
inline void push_up()
{
for(int i=0;i<=1;i++)
{
if(ch[i])
{
mx[0]=min(mx[0],ch[i]->mx[0]);
mx[1]=max(mx[1],ch[i]->mx[1]);
my[0]=min(my[0],ch[i]->my[0]);
my[1]=max(my[1],ch[i]->my[1]);
}
}
}
}pool_node[MAXN],*pool_top=pool_node;
node *del_pool[MAXN],**del_top=del_pool;
inline node* newnode()
{
return del_top==del_pool?++pool_top:*(del_top--);
}
struct Point
{
ll x,y;
int id;
bool operator < (const Point &a)const
{
if(x==a.x)
return y<a.y;
return x<a.x;
}
Point(){}
Point(ll _x,ll _y,int _id):x(_x),y(_y),id(_id){}
};
inline bool cmp_x(const Point &a,const Point &b) {return a.x<b.x;}
inline bool cmp_y(const Point &a,const Point &b) {return a.y<b.y;}
node **rebuild_need;
int rebuild_d;
Point stk[MAXN];
int point_cnt;
//用于最开始建树,可以不用直接插点,方法为build(1,point_cnt,0),保证点在stk数组中
node* build(int l,int r,bool f)
{
int mid=(l+r)>>1;
node *o=newnode();
nth_element(stk+l,stk+mid,stk+r+1,!f?cmp_x:cmp_y);
o->d[0]=o->mx[0]=o->mx[1]=stk[mid].x;
o->d[1]=o->my[0]=o->my[1]=stk[mid].y;
o->id=stk[mid].id;
o->ch[0]=l<mid?build(l,mid-1,f^1):0;
o->ch[1]=mid<r?build(mid+1,r,f^1):0;
o->push_up();
return o;
}
Point P,book;
ll ans;
ll calc_mn(node *o)//Manhattan距离下进行计算,如果是欧氏距离,则为max(P.x-o->mx[1],0)+max(o->mx[0]-P.x,0)的平方(本处表示到这个子树平面的最短距离)
{
ll ret=0;
ret+=(max(P.x-o->mx[1],0LL)+max(o->mx[0]-P.x,0LL))*(max(P.x-o->mx[1],0LL)+max(o->mx[0]-P.x,0LL));
ret+=(max(P.y-o->my[1],0LL)+max(o->my[0]-P.y,0LL))*(max(P.y-o->my[1],0LL)+max(o->my[0]-P.y,0LL));
return ret;
}
void Query_Min(node *o)//查询平面中到目标点最近的点
{
if(o->id!=P.id)
{
ll dis=((o->d[0]-P.x)*(o->d[0]-P.x)+(o->d[1]-P.y)*(o->d[1]-P.y));
if(dis==ans)
{
if(mp(o->d[0],o->d[1],o->id)<book)
{
book=mp(o->d[0],o->d[1],o->id);
}
}
else if(dis<ans)
{
book=mp(o->d[0],o->d[1],o->id);
ans=dis;
}
}
ll dl=o->ch[0]?calc_mn(o->ch[0]):inf;
ll dr=o->ch[1]?calc_mn(o->ch[1]):inf;
if(dl<dr)
{
if(dl<=ans)
Query_Min(o->ch[0]);
if(dr<=ans)
Query_Min(o->ch[1]);
}
else
{
if(dr<=ans)
Query_Min(o->ch[1]);
if(dl<=ans)
Query_Min(o->ch[0]);
}
}
node *root;
int Query(ll x,ll y,int id)
{
P=Point(x,y,id);
ans=inf;
Query_Min(root);
return book.id;
}
void del(node *&a)//用于清空整颗树
{
for(int i=0;i<=1;i++)
{
if(a->ch[i])
{
del(a->ch[i]);
}
}
a=NULL;
}
void init()//用于初始化
{
del_top=del_pool,pool_top=pool_node;
}
}
struct p
{
ll x,y;
}sv[MAXN];
struct Edge
{
int to,next;
}edge[MAXN*2];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~scc
int Index,top;
int scc;//强连通分量的个数
bool Instack[MAXN];
//num数组不一定需要,结合实际情况
void addedge(int u,int v)
{
edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;
}
void fi(int now)
{
int to=KD_Tree :: Query(sv[now].x,sv[now].y,now);
addedge(now,to);
addedge(to,now);
}
void Tarjan(int u)
{
int v;
Low[u]=DFN[u]=++Index;
Stack[top++]=u;
Instack[u]=true;
for(int i = head[u];i != -1;i = edge[i].next)
{
v=edge[i].to;
if(!DFN[v])
{
Tarjan(v);
if(Low[u]>Low[v])Low[u]=Low[v];
}
else if(Instack[v]&&Low[u]>DFN[v])
Low[u]=DFN[v];
}
if(Low[u]==DFN[u])
{
scc++;
do
{
v=Stack[--top];
Instack[v] = false;
Belong[v] = scc;
}
while(v!=u);
}
}
void solve(int N)
{
memset(DFN,0,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
Index=scc=top=0;
for(int i=1;i<=N;i++)
if(!DFN[i])
Tarjan(i);
}
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
for(int _=1;_<=T;_++)
{
int n,q;
KD_Tree :: init();
init();
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&KD_Tree :: stk[i].x,&KD_Tree :: stk[i].y);
KD_Tree :: stk[i].id=i;
sv[i].x=KD_Tree :: stk[i].x;
sv[i].y=KD_Tree :: stk[i].y;
}
KD_Tree :: root=KD_Tree :: build(1,n,0);
for(int i=1;i<=n;i++)
{
fi(i);
}
solve(n);
printf("Case #%d:\n",_);
for(int i=1;i<=q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(Belong[x]==Belong[y])
printf("YES\n");
else
printf("NO\n");
}
KD_Tree :: del(KD_Tree :: root);
}
return 0;
}