\(Solution\)

参考

对于每个点,向唯一有可能与它形成MST的8个点连边,由于是双向单边,所以每个点最多连出4条边(证明见blog

怎么找到一个区域内最近的点?

只考虑y轴右侧45°的区域,其余部分可以通过坐标变换移动到这一区域

设当前点P(x0,y0),这一区域一点P1(x1,y1),满足x1>x0 && y1-x1>y0-x0

那么dis(AB)= y1-y0+x1-x0 = x1+y1-(x0+y0)

这样这一区域内dis(AB)最小的点即 在满足之前条件的点中 x1+y1最小的点

先对x排序;then由于是只查询某个后缀,可以对y-x离散后用树状数组找到最小的x+y

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define lb(x) (x&-x)
#define gc() getchar()
#define dis(i,j) (std::abs(p[i].x-p[j].x)+std::abs(p[i].y-p[j].y))
const int N=5e4+5; int n,Enum,fa[N],A[N],ref[N];
struct Point
{
int x,y,id;
inline bool operator <(const Point &a)const {return x==a.x?y<a.y:x<a.x;}
}p[N];
struct Bit_Tree
{
int val[N],pos[N];
inline void Init() {memset(val,0x7f,sizeof val);}
void Update(int p,int v,int vp)
{
for(;p;p-=lb(p))
if(val[p]>v) val[p]=v,pos[p]=vp;
}
int Query(int p,int n)
{
int mn=1<<30,res=-1;
for(;p<=n;p+=lb(p))
if(mn>val[p]) mn=val[p],res=pos[p];
return res;
}
}t;
struct Edge
{
int to,fr,val;
inline bool operator <(const Edge &a)const {return val<a.val;}
}e[N<<2]; inline void AddEdge(int u,int v,int w)
{
e[++Enum].to=v, e[Enum].fr=u, e[Enum].val=w;
}
inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
int Getf(int x)
{
return x==fa[x]?x:fa[x]=Getf(fa[x]);
}
int MST()
{
for(int dir=0;dir<4;++dir)//坐标变换
{//Time1.不变
if(dir==1||dir==3)
for(int i=1;i<=n;++i) std::swap(p[i].x,p[i].y);//T2.T4.关于y=x对称
else if(dir==2)
for(int i=1;i<=n;++i) p[i].x=-p[i].x;//T3.关于x=0对称
std::sort(p+1,p+1+n);
t.Init();
for(int i=1;i<=n;++i) A[i]=ref[i]=p[i].y-p[i].x;
std::sort(A+1,A+1+n);
int m=1; ref[1]=A[1];
for(int i=2;i<=n;++i)
if(A[i]!=A[i-1]) ref[++m]=A[i];
for(int pos,res,i=n;i;--i)
{
pos=std::lower_bound(ref+1,ref+1+m,p[i].y-p[i].x)-ref;
if((res=t.Query(pos,m))!=-1) AddEdge(p[i].id,p[res].id,dis(i,res));
t.Update(pos,p[i].x+p[i].y,i);
}
}
std::sort(e+1,e+1+Enum);
for(int i=1;i<=n;++i) fa[i]=i;
int res=0;
for(int r1,r2,i=1,k=0;i<=Enum;++i)
{
r1=Getf(e[i].fr),r2=Getf(e[i].to);
if(r1!=r2)
{
res+=e[i].val, fa[r1]=r2;
if(++k==n-1) break;
}
}
return res;
} int main()
{
n=read();
for(int i=1;i<=n;++i) p[i].x=read(),p[i].y=read(),p[i].id=i;
printf("%d",MST());
return 0;
}

BZOJ.2177.曼哈顿最小生成树(Kruskal)的更多相关文章

  1. BZOJ 2177: 曼哈顿最小生成树

    Sol 考了好几次曼哈顿最小生成树,然而一直不会打...这次终于打出来了...神tm调试了2h...好蛋疼... 首先曼哈顿最小生成树有个结论就是讲它每45度分出一个象限,对于每个点,只与每个象限中离 ...

  2. 【BZOJ-2177】曼哈顿最小生成树 Kruskal + 树状数组

    2177: 曼哈顿最小生成树 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 190  Solved: 77[Submit][Status][Discu ...

  3. poj 3241 Object Clustering (曼哈顿最小生成树)

    Object Clustering Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 2640   Accepted: 806 ...

  4. POJ3241 Object Clustering 曼哈顿最小生成树

    题意:转换一下就是求曼哈顿最小生成树的第n-k条边 参考:莫涛大神的论文<平面点曼哈顿最小生成树> /* Problem: 3241 User: 96655 Memory: 920K Ti ...

  5. 模板——最小生成树kruskal算法+并查集数据结构

    并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每 ...

  6. 最小生成树——Kruskal与Prim算法

    最小生成树——Kruskal与Prim算法 序: 首先: 啥是最小生成树??? 咳咳... 如图: 在一个有n个点的无向连通图中,选取n-1条边使得这个图变成一棵树.这就叫“生成树”.(如下图) 每个 ...

  7. 【转】最小生成树——Kruskal算法

    [转]最小生成树--Kruskal算法 标签(空格分隔): 算法 本文是转载,原文在最小生成树-Prim算法和Kruskal算法,因为复试的时候只用到Kruskal算法即可,故这里不再涉及Prim算法 ...

  8. BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )

    不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...

  9. BZOJ.1016.[JSOI2008]最小生成树计数(Matrix Tree定理 Kruskal)

    题目链接 最小生成树有两个性质: 1.在不同的MST中某种权值的边出现的次数是一定的. 2.在不同的MST中,连接完某种权值的边后,形成的连通块的状态是一样的. \(Solution1\) 由这两个性 ...

随机推荐

  1. C++学习8-面向对象编程基础(模板)

    模板 模板是一种工具,模板可以使程序员能建立具有通用类型的函数库与类库: 模板具有两种不同的形式: 函数模板 类模板 函数模板 当一个add()函数接收两个参数,因为某种特定情况,所传入的实参数据类型 ...

  2. A1pass大大对黑客学习的建议

    本文转自:http://bbs.hackav.com/thread-92-1-1.html 菜鸟不可怕,可怕的是你认为自己一辈子都是菜鸟.每个高手都是从菜鸟进化过来的,就算是现在黑客界的泰斗们当年也无 ...

  3. 利用grub从ubuntu找回windows启动项

    在 /boot/grub/grub.cfg 中添加: menuentry "Windows 10" --class windows --class os { insmod ntfs ...

  4. ruia笔记

    ruia笔记 loop = loop or asyncio.new_event_loop() get_event_loop()方法仅在同样的线程中生效,如果在一个新线程中,应该用new_event_l ...

  5. mybatis框架之foreach标签

    foreach一共有三种类型,分别为List,[](array),Map三种,下面表格是我总结的各个属性的用途和注意点. foreach属性 属性 描述 item 循环体中的具体对象.支持属性的点路径 ...

  6. 转载:Java中的字符串常量池详细介绍

    引用自:http://blog.csdn.net/langhong8/article/details/50938041 这篇文章主要介绍了Java中的字符串常量池详细介绍,JVM为了减少字符串对象的重 ...

  7. Linux内核移植

    实验步骤:(1)准备工作(2)修改顶层Makefile(3)修改falsh 分区(4)配置编译内核 下面以Linux2.6.30.4内核移植到gec2440为例: 一.准备工作:建立工作目录,下载内核 ...

  8. [学习笔记]Javascript采用二进制浮点数和四舍五入的错误

    1.样例 var a = .3 - .2 //0.09999999999999998 var b = .2 - .1 //0.1 a == b //false 出现这样的原因在于 1.Javascri ...

  9. Fiddler抓包9-保存会话(save)

    前言 为什么要保存会话呢?举个很简单的场景,你在上海测试某个功能接口的时候,发现了一个BUG,而开发这个接口的开发人员是北京的一家合作公司.你这时候给对方开发提bug, 如何显得专业一点,能让对方心服 ...

  10. JavaScript实现抽象类与虚方法(六)

    一:什么是js抽象类与虚方法 虚函数是类成员中的概念,是只做了一个声明而未实现的方法,具有虚函数的类就称之为抽象类,这些虚函数在派生类中才被实现.抽象类是不能实例化的,因为其中的虚函数并不是一个完整的 ...