HDU 5809 Ants(KD树+并查集)
【题目链接】 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树+并查集)的更多相关文章
- HDU 1512 左偏树+并查集
思路: 左偏树里面掺了一些并查集的应用 这里放一份左偏树的代码模板 重点就是merge函数了-- int merge(int k1,int k2){ if(!k1||!k2)return k1+k2; ...
- [WC2005]双面棋盘(线段树+并查集)
线段树+并查集维护连通性. 好像 \(700ms\) 的时限把我的常数超级大的做法卡掉了, 必须要开 \(O_2\) 才行. 对于线段树的每一个结点都开左边的并查集,右边的并查集,然后合并. \(Co ...
- 洛谷 - P1552 - 派遣 - 左偏树 - 并查集
首先把这个树建出来,然后每一次操作,只能选中一棵子树.对于树根,他的领导力水平是确定的,然后他更新答案的情况就是把他子树内薪水最少的若干个弄出来. 问题在于怎么知道一棵子树内薪水最少的若干个分别是谁. ...
- 洛谷 - P3377 - 【模板】左偏树(可并堆) - 左偏树 - 并查集
https://www.luogu.org/problemnew/show/P3377 左偏树+并查集 左偏树维护两个可合并的堆,并查集维护两个堆元素合并后可以找到正确的树根. 关键点在于删除一个堆的 ...
- 2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集)
2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集) https://www.luogu.com.cn/problem/CF811E Ste ...
- HDU 1512 Monkey King(左偏树+并查集)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=1512 [题目大意] 现在有 一群互不认识的猴子,每个猴子有一个能力值,每次选择两个猴子,挑出他们所 ...
- hdu 3172 Virtual Friends(并查集,字典树)
题意:人与人交友构成关系网,两个人交友,相当于两个朋友圈的合并,问每个出两人,他们目前所在的关系网中的人数. 分析:用并查集,其实就是求每个集合当前的人数.对于人名的处理用到了字典树. 注意:1.题目 ...
- HDU 1512 Monkey King (左偏树+并查集)
题意:在一个森林里住着N(N<=10000)只猴子.在一开始,他们是互不认识的.但是随着时间的推移,猴子们少不了争斗,但那只会发生在互不认识 (认识具有传递性)的两只猴子之间.争斗时,两只猴子都 ...
- HDU - 1272 小希的迷宫 并查集判断无向环及连通问题 树的性质
小希的迷宫 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一 ...
随机推荐
- hdu 5755 Gambler Bo 高斯消元
题目链接 给n*m的方格, 每个格子有值{0, 1, 2}. 然后可以对格子进行操作, 如果选择了一个格子, 那么这个格子的值+2, 这个格子上下左右的格子+1, 并且模3. 问你将所有格子变成0的操 ...
- 初学swift笔记变量的定义(一)
swift变量的定义 1 import Foundation /* 变量的定义 变量的类型是可以不用写的 var a=10 常量的定义 let修饰 */ print(a) let b= print(b ...
- 通过实例深入理解lec和yacc
本框架是一个lex/yacc完整的示例,包括详细的注释,用于学习lex/yacc程序基本的搭建方法,在linux/cygwin下敲入make就可以编译和执行.大部分框架已经搭好了,你只要稍加扩展就可以 ...
- Asp.net MVC1 学习1
此次博客的编写纯属是为了记录自己的学习情况 asp.net mvc学习教程来自于重点,地址:http://v.youku.com/v_show/id_XNDQ4MDQ1MzI=.html?f=2416 ...
- NET Core开发-读取配置文件Configuration
ASP.NET Core开发-读取配置文件Configuration ASP.NET Core 是如何读取配置文件,今天我们来学习. ASP.NET Core的配置系统已经和之前版本的ASP.NE ...
- C++ typeid实现原理
最近看了boost::any类源码,其实现主要依赖typeid操作符.很好奇这样实现的时间和空间开销有多大,决定探一下究竟. VS2008附带的type_info类只有头文件,没有源文件,声明如下: ...
- OpenRisc-48-or1200的SPRS模块分析
引言 之前,我们在分析or1200的WB模块时(http://blog.csdn.net/rill_zhen/article/details/10220619),介绍了OpenRISC的GPRS(ge ...
- Python导入模块的三种形式
Python导入模块的3中方式: 1.import module_name 这样在程序里就可以通过module_name.metnod_name()的方式访问模块里的函数了 Example: > ...
- ASP.NET repeater添加序号列的方法
ASP.NET repeater添加序号列的方法 1.<itemtemplate> <tr><td> <%# Container.ItemIndex + 1% ...
- 在magento中定义static block
在magento中如何调用static block?(系统面板内CMS---->static block) 解答:若想在站点页面的某个地方放点静态的内容,比如广告,或者是促销信息之类的,这样的东 ...