【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=5809

【题目大意】

  给出一些蚂蚁和他们的巢穴,一开始他们会在自己的巢穴(以二维坐标形式给出),之后每一个时刻会向距离自己最近的巢穴移动,当两只蚂蚁相向而行的时候,我们可以认为他们相遇了,现在有q个询问,每个询问需要让你判断蚂蚁x和y是否会相遇。

【题解】

  我们可以发现对于一只蚂蚁来说,他最后肯定会陷入一个二元环中来回走动,那么我们只要判断是否最后两只蚂蚁会出现在同一个二元环中,那么就可以判断他们是否可以相遇。

  首先对于所有点构建KD树,对于每个点计算离它最近的点,将两个点加入同一个集合,最后判断询问两点是否属于同一个集合即可,集合的合并和判断可以用并查集实现。

【代码】

#include <cstdio>
#include <algorithm>
const int N=400010;
int n,i,id[N],root,cmp_d;
typedef long long LL;
const LL INF=0x3f3f3f3f3f3f3f3fLL;
struct node{
int d[2],l,r,Max[2],Min[2],val,sum,f,id;
bool operator<(const node& B){return d[0]<B.d[0]||(d[0]==B.d[0]&&d[1]<B.d[1]);}
}t[N];
inline bool cmp(const node&a,const node&b){return a.d[cmp_d]<b.d[cmp_d];}
inline void umax(int&a,int b){if(a<b)a=b;}
inline void umin(int&a,int b){if(a>b)a=b;}
inline void up(int x){
if(t[x].l){
umax(t[x].Max[0],t[t[x].l].Max[0]);
umin(t[x].Min[0],t[t[x].l].Min[0]);
umax(t[x].Max[1],t[t[x].l].Max[1]);
umin(t[x].Min[1],t[t[x].l].Min[1]);
}
if(t[x].r){
umax(t[x].Max[0],t[t[x].r].Max[0]);
umin(t[x].Min[0],t[t[x].r].Min[0]);
umax(t[x].Max[1],t[t[x].r].Max[1]);
umin(t[x].Min[1],t[t[x].r].Min[1]);
}
}
int build(int l,int r,int D,int f){
int mid=(l+r)>>1;
cmp_d=D,std::nth_element(t+l+1,t+mid+1,t+r+1,cmp);
id[t[mid].f]=mid;
t[mid].f=f;
t[mid].Max[0]=t[mid].Min[0]=t[mid].d[0];
t[mid].Max[1]=t[mid].Min[1]=t[mid].d[1];
t[mid].val=t[mid].sum=0;
if(l!=mid)t[mid].l=build(l,mid-1,!D,mid);else t[mid].l=0;
if(r!=mid)t[mid].r=build(mid+1,r,!D,mid);else t[mid].r=0;
return up(mid),mid;
}
inline LL sqr(int x){return (LL)x*x;}
LL ans; node ansP;
LL ans2; node ansP2;
int px,py;
inline LL dist(int p1){
LL dis=0;
if(px<t[p1].Min[0])dis+=sqr(t[p1].Min[0]-px);
if(px>t[p1].Max[0])dis+=sqr(px-t[p1].Max[0]);
if(py<t[p1].Min[1])dis+=sqr(t[p1].Min[1]-py);
if(py>t[p1].Max[1])dis+=sqr(py-t[p1].Max[1]);
return dis;
}
void ask(int x){
LL dl,dr,d0=sqr(t[x].d[0]-px)+sqr(t[x].d[1]-py);
if(d0<ans||(d0==ans&&t[x]<ansP))ans2=ans,ansP2=ansP,ans=d0,ansP=t[x];
else if(d0<ans2||(d0==ans2&&t[x]<ansP2))ans2=d0,ansP2=t[x];
dl=t[x].l?dist(t[x].l):INF;
dr=t[x].r?dist(t[x].r):INF;
if(dl<dr){
if(dl<=ans2)ask(t[x].l);
if(dr<=ans2)ask(t[x].r);
}else{
if(dr<=ans2)ask(t[x].r);
if(dl<=ans2)ask(t[x].l);
}
}
int getP(int root){
ans=ans2=INF; ask(root); return ansP2.id;
}
int T,x,y,Cas=1,q,f[N];
int sf(int x){return f[x]==x?f[x]:f[x]=sf(f[x]);}
int main(){
scanf("%d",&T);
while(T--){
printf("Case #%d:\n",Cas++);
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d%d",&x,&y);
t[i].d[0]=x,t[i].d[1]=y,t[i].id=i;
}root=build(1,n,0,0);
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=n;i++){
px=t[i].d[0],py=t[i].d[1];
x=t[i].id,y=getP(root);
f[sf(x)]=sf(y);
}
while(q--){
scanf("%d%d",&x,&y);
puts(sf(x)==sf(y)?"YES":"NO");
}
}return 0;
}

HDU 5809 Ants(KD树+并查集)的更多相关文章

  1. HDU 1512 左偏树+并查集

    思路: 左偏树里面掺了一些并查集的应用 这里放一份左偏树的代码模板 重点就是merge函数了-- int merge(int k1,int k2){ if(!k1||!k2)return k1+k2; ...

  2. [WC2005]双面棋盘(线段树+并查集)

    线段树+并查集维护连通性. 好像 \(700ms\) 的时限把我的常数超级大的做法卡掉了, 必须要开 \(O_2\) 才行. 对于线段树的每一个结点都开左边的并查集,右边的并查集,然后合并. \(Co ...

  3. 洛谷 - P1552 - 派遣 - 左偏树 - 并查集

    首先把这个树建出来,然后每一次操作,只能选中一棵子树.对于树根,他的领导力水平是确定的,然后他更新答案的情况就是把他子树内薪水最少的若干个弄出来. 问题在于怎么知道一棵子树内薪水最少的若干个分别是谁. ...

  4. 洛谷 - P3377 - 【模板】左偏树(可并堆) - 左偏树 - 并查集

    https://www.luogu.org/problemnew/show/P3377 左偏树+并查集 左偏树维护两个可合并的堆,并查集维护两个堆元素合并后可以找到正确的树根. 关键点在于删除一个堆的 ...

  5. 2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集)

    2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集) https://www.luogu.com.cn/problem/CF811E Ste ...

  6. HDU 1512 Monkey King(左偏树+并查集)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=1512 [题目大意] 现在有 一群互不认识的猴子,每个猴子有一个能力值,每次选择两个猴子,挑出他们所 ...

  7. hdu 3172 Virtual Friends(并查集,字典树)

    题意:人与人交友构成关系网,两个人交友,相当于两个朋友圈的合并,问每个出两人,他们目前所在的关系网中的人数. 分析:用并查集,其实就是求每个集合当前的人数.对于人名的处理用到了字典树. 注意:1.题目 ...

  8. HDU 1512 Monkey King (左偏树+并查集)

    题意:在一个森林里住着N(N<=10000)只猴子.在一开始,他们是互不认识的.但是随着时间的推移,猴子们少不了争斗,但那只会发生在互不认识 (认识具有传递性)的两只猴子之间.争斗时,两只猴子都 ...

  9. HDU - 1272 小希的迷宫 并查集判断无向环及连通问题 树的性质

    小希的迷宫 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一 ...

随机推荐

  1. 【译】Optimize caching-缓存优化

    缓存优化 大部分的网页都包括不常更改的资源,比如CSS文件,图片文件,JavaScript文件等.这些资源通过网络下载需要一定的时间,这就增加了网页加载的总时间.HTTP缓存可以让这些资源通过浏览器以 ...

  2. python学习day2(二)

    1.类与对象的关系 对于Python,一切事物都是对象,对象基于类创建 type是获取类的 dir是获取这个类里面的成员 2.int内部功能介绍 bit_length:返回表示当前数字占用的最少位数: ...

  3. Struts2命名空间问题

    警告: No configuration found for the specified action: '/myNameSpace/login.action' in names 今天花了点时间把st ...

  4. 支持SMTP邮箱介绍

    126邮箱:POP:POP.126.comSMTP:SMTP.126.comhttp://mail.126.com/help/client_04.htm 163邮箱:POP:pop.163.comSM ...

  5. 练习3.20 a 将中缀表达式转换为后缀表达式

    //将中缀表达式转换为后缀表达式 int main() { ; ]={,,,,,,,}; char tmp; PtrToStack s; s = CreateStack( MaxSize ); ) { ...

  6. 线性表A-B

    1.顺序存储 #include<stdio.h> /* 设有两个顺序表A和B,且都递增有序,试写一算法,从A中删除与B中相同的那些元素,即求A-B */ #define getArrayL ...

  7. Linux学习笔记3-VI 和 VIM的使用

    vi: Visual Interface vim: VI iMproved 全屏编辑器, Linux系统下最强大的两款编辑器,vi和vim,vi是Linux本身自带的一款编辑器,纯文本编辑不带任何效果 ...

  8. 郁闷的C小加(一)(后缀表达式)

    郁闷的C小加(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 我们熟悉的表达式如a+b.a+b*(c+d)等都属于中缀表达式.中缀表达式就是(对于双目运算符来说 ...

  9. android 网络状态判断【转】

    import java.net.InetAddress; import android.app.Activity;import android.content.Context;import andro ...

  10. Exception Handling in ASP.NET Web API

    public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErr ...