【BZOJ-2177】曼哈顿最小生成树 Kruskal + 树状数组
2177: 曼哈顿最小生成树
Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 190 Solved: 77
[Submit][Status][Discuss]
Description
平面坐标系xOy内,给定n个顶点V = (x , y)。对于顶点u、v,u与v之间的距离d定义为|xu – xv| + |yu – yv| 你的任务就是求出这n个顶点的最小生成树。
Input
第一行一个正整数n,表示定点个数。
接下来n行每行两个正整数x、y,描述一个顶点。
Output
只有一行,为最小生成树的边的距离和。
Sample Input
1 0
0 1
0 -1
-1 0
Sample Output
HINT
Source
Solution
曼哈顿距离最小生成树裸题
那么来说一下曼哈顿距离最小生成树
首先给出$N$个点,求普通的最小生成树,Kruskal的时间复杂度是$O(MlogN)$,显然$M$的级别是$N^{2}$的,但曼哈顿距离最小生成树能做到$O(NlogN)$
先考虑最小生成树的一个性质:如果图中存在一个环,那么把环上最大边删掉,得到的与不删环的MST权和是一样的
利用这个性质,我们构建边的时候,就能大大减少边的数量
考虑现在在一个点$S$,可以从这个点为中心,把平面分成8份
然后我们发现,在一个象限中,点$S$至多和一个点相连的边是有用的。
先说一个自己的理解但不是很详尽的证明;

我们考虑,如果全都连边,大概是这样的情况,但是我们发现,$|AC|<|AB| && |CB|<|AB|$
那么考虑环切定理,这样,边AB是可以删去的,所以很容易理解每个点只需要连象限中离他最近的点即可
证明:
八个扇形区域是对称的,我们只考虑R1。
把s看作原点,R1里面的点(x,y)都满足:
x≥0,
y>x.
考察R1里面两个点p和q,不失一般性设xp≤xq。
1. yp≤yq
|PQ|=xq+yq-(xp+xq)
|SP|=xp+yp
|SQ|=xq+yq
所以|PQ|=|SQ|-|SP|≤|SQ|
可见当yp≤yq时,|PQ|不是三角形SPQ的最长边。(在曼哈顿距离下的“最长”)
2. yp>yq
0≤xp≤xq≤yq<yp
|PQ|=xq-xp+yp-yq
|SP|=xp+yp
|SQ|=xq+yq
即|PQ|= (yp-xp)+(xq-yq)
因为xq≤yq,所以|PQ|≤yp-xp≤yp≤xp+yp=|SP|
也就是说,当yp>yq时,|PQ|仍然不是三角形SPQ的最长边。(曼哈顿距离意义下的“最长”)
综上,|PQ|无论如何也不可能是三角形SPQ的最长边。即:在环<s, p, q>中,最大边只可能是|SP|和|SQ|。根据“环切”性质,我们把|SP|和|SQ|中的较长边删除即可。
假设R1里面有m个顶点:P1, P2, …, Pm,假设距离s最近的点是Pk,那么只要在S和Pk之间连边即可。
所谓距离s最近的点,实际上就是xk+yk最小的点。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXN 100010
int N;
struct PointNode{int x,y,id;}P[MAXN];
bool cmpP(PointNode A,PointNode B) {return A.x!=B.x? A.x<B.x : A.y<B.y;}
struct UnionFind
{
int Fa[MAXN];
void Init() {for (int i=; i<=N; i++) Fa[i]=i;}
int Find(int x) {if (Fa[x]==x) return x; else return Fa[x]=Find(Fa[x]);}
bool Merge(int x,int y) {int f1=Find(x),f2=Find(y); if (f1==f2) return ; Fa[f1]=f2; return ;}
}uf;
int Dis(PointNode A,PointNode B) {return abs(A.x-B.x)+abs(A.y-B.y);}
struct EdgeNode{int to,val,from;}edge[MAXN<<];
int cnt;
void AddEdge(int u,int v,int w) {cnt++; edge[cnt].from=u; edge[cnt].to=v; edge[cnt].val=w;}
bool cmpE(EdgeNode A,EdgeNode B) {return A.val<B.val;}
int lowbit(int x) {return x&-x;}
struct BITNode{int minn,pos; void init() {minn=0x7fffffff; pos=-;}}bit[MAXN];
void Update(int x,int val,int pos)
{
for (int i=x; i; i-=lowbit(i))
if (val<bit[i].minn) bit[i].minn=val,bit[i].pos=pos;
}
int Query(int x,int M)
{
int minn=0x7fffffff,pos=-;
for (int i=x; i<=M; i+=lowbit(i))
if (bit[i].minn<minn) minn=bit[i].minn,pos=bit[i].pos;
return pos;
}
int num,Ans;
void MST()
{
int a[MAXN],b[MAXN];
for (int k=; k<=; k++)
{
if (k== || k==) for (int i=; i<=N; i++) swap(P[i].x,P[i].y);
else if (k==) for (int i=; i<=N; i++) P[i].x=-P[i].x;
stable_sort(P+,P+N+,cmpP);
for (int i=; i<=N; i++)
a[i]=b[i]=P[i].y-P[i].x;
stable_sort(b+,b+N+);
int M=unique(b+,b+N+)-b-;
for (int i=; i<=M; i++) bit[i].init();
for (int i=N; i>=; i--)
{
int pos=lower_bound(b+,b+M+,a[i])-b;
int ans=Query(pos,M);
if (ans!=-) AddEdge(P[i].id,P[ans].id,Dis(P[i],P[ans]));
Update(pos,P[i].x+P[i].y,i);
}
}
stable_sort(edge+,edge+cnt+,cmpE);
uf.Init();
for (int i=; i<=cnt; i++)
{
int u=edge[i].from,v=edge[i].to;
if (uf.Merge(u,v)) Ans+=edge[i].val,num++;
if (num==N-) break;
}
}
int main()
{
N=read();
for (int i=; i<=N; i++) P[i].x=read(),P[i].y=read(),P[i].id=i;
MST();
printf("%d\n",Ans);
return ;
}
感觉很愚蠢的代码
【BZOJ-2177】曼哈顿最小生成树 Kruskal + 树状数组的更多相关文章
- BZOJ.2177.曼哈顿最小生成树(Kruskal)
\(Solution\) 参考 对于每个点,向唯一有可能与它形成MST的8个点连边,由于是双向单边,所以每个点最多连出4条边(证明见blog) 怎么找到一个区域内最近的点? 只考虑y轴右侧45°的区域 ...
- BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树
[题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...
- [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】
题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...
- BZOJ 2743: [HEOI2012]采花 [树状数组 | 主席树]
题意: 查询区间中出现次数$>2$的颜色个数 一眼主席树,区间中$l \le last[i] \le r$的个数减去$l \le last[last[i]] \le r$的个数,搞两颗主席树来做 ...
- BZOJ.4826.[AHOI/HNOI2017]影魔(树状数组/莫队 单调栈)
BZOJ LOJ 洛谷 之前看\(mjt\)用莫队写了,以为是一种正解,码了3h结果在LOJ T了没A= = 心态爆炸(upd:发现是用C++11(NOI)交的,用C++11交就快一倍了...) 深刻 ...
- bzoj 3262 陌上花开 - CDQ分治 - 树状数组
Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...
- bzoj 2527 Meteors - 整体二分 - 树状数组
Description Byteotian Interstellar Union (BIU) has recently discovered a new planet in a nearby gala ...
- BZOJ 3224 普通平衡树(树状数组)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3224 题意:维护以下操作:(1)插入x:(2)删除x(若有多个相同的数,只删除一个)(3 ...
- Bzoj 3339: Rmq Problem && Bzoj 3585: mex 莫队,树状数组,二分
3339: Rmq Problem Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 833 Solved: 397[Submit][Status][D ...
随机推荐
- js物理弹性窗口
js物理弹性窗口 点击下载代码
- HTML5商城开发四 多图或多商品的水平滚动展示
一.效果图 二.实现 样式: .horz_scroll { float: left; width: 20px; height: 130px; padding-top: 100px; padding-l ...
- BZOJ 1014 【JSOI2008】 火星人prefix
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- 用C++11的std::async代替线程的创建
c++11中增加了线程,使得我们可以非常方便的创建线程,它的基本用法是这样的: void f(int n); std::thread t(f, n + 1); t.join(); 但是线程毕竟是属于比 ...
- realmswift的使用
官网:https://realm.io/ 1.说下数据库迁移的问题: 在func application(application: UIApplication, didFinishLaunchingW ...
- 建立时间和保持时间(setup time 和 hold time)
建立时间和保持时间贯穿了整个时序分析过程.只要涉及到同步时序电路,那么必然有上升沿.下降沿采样,那么无法避免setup-time 和 hold-time这两个概念.本文内容相对独立于该系列其他文章,是 ...
- 网站集成QQ登录功能
最近在做一个项目时,客户要求网站能够集成QQ登录的功能,以前没做过这方面的开发,于是去QQ的开放平台官网研究了一下相关资料,经过自己的艰苦探索,终于实现了集成QQ登录的功能,现在把相关的开发经验总结一 ...
- web性能优化——简介
简介 性能优化的第一准则:加缓存.几乎绝大部分优化都围绕这个来进行的.让用户最快的看到结果. 性能优化的第二准则:最小原则.绝不提供多余的信息.比如,静态资源(图片.css.js)压缩,图片的滚动加载 ...
- 2016年1月25日 《1024伐木累》-小白篇之开发网站,三天!(中篇-2奇怪的IE)-总章节十一
往期回顾: 老王的“先见之明”,解决了困扰耗仔三人的大难题.顺利安装完开发工具,大家投入紧张的工作.航空部领导的突然闯入,IE不兼容,页面错乱,摆在三人面前的形势依然严峻.第一次见这阵仗的耗仔,又会 ...
- 深入理解计算机系统(4.1)---X86的孪生兄弟,Y86指令体系结构
引言 各位猿友们好,计算机系统系列很久没更新了,实在是抱歉之极.新的一年,为了给计算机系统系列添加一些新的元素,LZ将其更改为书的原名<深入理解计算机系统>.这本书非常厚,而且难度较高,L ...