Sol

考了好几次曼哈顿最小生成树,然而一直不会打...这次终于打出来了...神tm调试了2h...好蛋疼...

首先曼哈顿最小生成树有个结论就是讲它每45度分出一个象限,对于每个点,只与每个象限中离他最近的点连线,做最小生成树,就是他们的曼哈顿最小生成树.

关于证明,先让我想想再来补.

我们的问题两个方面:为什么将平面分成8块;为什么只需要连接每块中距离最小的点.

不过好像没人稀罕说第一个问题...我自己yy了一下,感觉挺科学的...将平面分成8块的原因就是两个点计算距离的时候去掉绝对值后有8种可能.

\(Dis(A,B)=\pm (x_A-x_B)\pm (y_A-y_B)\) 这样就有4种结果,然后A,B位置可以互换,这样就是8种了...然后分成8个部分...唔...好像是这样吧..

(欢迎打脸~)

证明:如下图,对于每三个这样的点,最小生成树显然是割掉矩形的一个角,使割掉的边尽量的大就好,最后在这个区域就只会剩下一个与它相连点,同时也是最近的一个点.

(这个也是我自己yy的qwq.可能不太完整,甚至是错误的...不过欢迎来打脸...)

因为边数是 \(4n\) 的,所以用Kruskal做最小生成树的复杂度 \(O(nlogn)\) .

至于8个方向只需要选择一个半平面连线就可以了,因为边是双向的.

这样就需要处理4块,这四块可以由一块通过关于y轴对称,关于直线x=y对称和关于y轴对称后再关于x=y对称.

PS:代码调试宛如智障.

Code

#include<cstdio>
#include<cstring>
#include<vector>
#include<utility>
#include<queue>
#include<algorithm>
#include<iostream>
using namespace std; #define mpr(a,b) make_pair(a,b)
const int N = 50005; int n,ans;
struct seat{ int x,y,id; }a[N],b[N];
bool operator < (const seat &a,const seat &b){ return a.x==b.x?a.y>b.y:a.x>b.x; }
int d[N<<1],id[N<<1],cnt,ys[N];
struct Edge{ int u,v,w; };
bool operator < (const Edge &a,const Edge &b){ return a.w>b.w; }
priority_queue<Edge> q;
int f[N]; inline int in(int x=0,char ch=getchar(),int v=1){
while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();if(ch=='-') v=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*v; }
//int cmpx(const seat &a,const seat &b){ return a.x==b.x?a.x<b.x:a.y<b.y; }
//int cmpxy(const seat &a,const seat &b){ return a.y-a.x<b.y-b.x; }
inline int abs(int x){ return x<0?-x:x; }
int find(int x){ return f[x]==x?x:f[x]=find(f[x]); }
void Add_Edge(int u,int v){
int dis=abs(a[u].x-a[v].x)+abs(a[u].y-a[v].y);
q.push((Edge){ u,v,dis });
}
void Add(int x,int v,int pos){
for(;x;x-=x&-x) if(d[x]>v) d[x]=v,id[x]=pos;
}
int Query(int x){
int minv=0x7f7f7f7f,pos=-1;
for(;x<=cnt;x+=x&-x) if(d[x]<minv) minv=d[x],pos=id[x];
return pos;
}
void out(seat a){ cout<<a.x<<" "<<a.y<<" "<<a.id<<endl<<"***************\n"; }
void Build(){
/* Part1 x1>x0&&y1-x1>y0-x0 dis=(x1+y1)-(x0+y0) */
memset(d,0x7f,sizeof(d)),memset(id,-1,sizeof(id)),memset(ys,0,sizeof(ys));cnt=0;
for(int i=1;i<=n;i++) b[i]=a[i];
// for(int i=1;i<=n;i++) out(a[i]);
sort(b+1,b+n+1);
// for(int i=1;i<=n;i++) out(b[i]);
for(int i=1;i<=n;i++) ys[i]=b[i].y-b[i].x;
sort(ys+1,ys+n+1);
cnt=unique(ys+1,ys+n+1)-ys-1; // cout<<cnt<<endl;
// for(int i=1;i<=cnt;i++) cout<<ys[i]<<" ";cout<<endl; for(int i=1;i<=n;i++){
int x=lower_bound(ys+1,ys+cnt+1,b[i].y-b[i].x)-ys;
int pos=Query(x);
if(~pos) Add_Edge(b[i].id,pos);
// cout<<b[i].id<<"-->"<<pos<<endl;
Add(x,b[i].x+b[i].y,b[i].id);
}
/* Part2 swap(x,y) */
memset(d,0x7f,sizeof(d)),memset(id,-1,sizeof(id)),memset(ys,0,sizeof(ys));cnt=0;
for(int i=1;i<=n;i++) b[i].y=a[i].x,b[i].x=a[i].y,b[i].id=a[i].id;
sort(b+1,b+n+1);
// for(int i=1;i<=n;i++) out(b[i]);
for(int i=1;i<=n;i++) ys[i]=b[i].y-b[i].x;
sort(ys+1,ys+n+1);
cnt=unique(ys+1,ys+n+1)-ys-1; // cout<<cnt<<endl;
// for(int i=1;i<=cnt;i++) cout<<ys[i]<<" ";cout<<endl; for(int i=1;i<=n;i++){
int x=lower_bound(ys+1,ys+cnt+1,b[i].y-b[i].x)-ys;
int pos=Query(x);
if(~pos) Add_Edge(b[i].id,pos);
// cout<<b[i].id<<"-->"<<pos<<endl;
Add(x,b[i].x+b[i].y,b[i].id);
} /* Part3 y=-y */
memset(d,0x7f,sizeof(d)),memset(id,-1,sizeof(id)),memset(ys,0,sizeof(ys));cnt=0;
for(int i=1;i<=n;i++) b[i]=a[i],b[i].y=-b[i].y;
sort(b+1,b+n+1);
// for(int i=1;i<=n;i++) out(b[i]);
for(int i=1;i<=n;i++) ys[i]=b[i].y-b[i].x;
sort(ys+1,ys+n+1);
cnt=unique(ys+1,ys+n+1)-ys-1; // cout<<cnt<<endl;
// for(int i=1;i<=cnt;i++) cout<<ys[i]<<" ";cout<<endl; for(int i=1;i<=n;i++){
int x=lower_bound(ys+1,ys+cnt+1,b[i].y-b[i].x)-ys;
int pos=Query(x);
if(~pos) Add_Edge(b[i].id,pos);
// cout<<b[i].id<<"-->"<<pos<<endl;
Add(x,b[i].x+b[i].y,b[i].id);
} /* Part4 swap(x,y) y=-y */
memset(d,0x7f,sizeof(d)),memset(id,-1,sizeof(id)),memset(ys,0,sizeof(ys));cnt=0;
for(int i=1;i<=n;i++) b[i].x=-a[i].y,b[i].y=a[i].x,b[i].id=a[i].id;
sort(b+1,b+n+1);
// for(int i=1;i<=n;i++) out(b[i]);
for(int i=1;i<=n;i++) ys[i]=b[i].y-b[i].x;
sort(ys+1,ys+n+1);
cnt=unique(ys+1,ys+n+1)-ys-1; // cout<<cnt<<endl;
// for(int i=1;i<=cnt;i++) cout<<ys[i]<<" ";cout<<endl; for(int i=1;i<=n;i++){
int x=lower_bound(ys+1,ys+cnt+1,b[i].y-b[i].x)-ys;
int pos=Query(x);
if(~pos) Add_Edge(b[i].id,pos);
// cout<<b[i].id<<"-->"<<pos<<endl;
Add(x,b[i].x+b[i].y,b[i].id);
}
/* MST */
for(int i=1;i<=n;i++) f[i]=i;
for(int k=1;!q.empty();){
Edge e=q.top();q.pop();
int u=e.u,v=e.v;
int f1=find(u),f2=find(v);
if(f1!=f2) k++,f[f2]=f1,ans+=e.w;
if(k>=n) break;
}cout<<ans<<endl;
}
int main(){
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
n=in();for(int i=1;i<=n;i++) a[i].x=in(),a[i].y=in(),a[i].id=i;
Build();
return 0;
}

  

BZOJ 2177: 曼哈顿最小生成树的更多相关文章

  1. BZOJ.2177.曼哈顿最小生成树(Kruskal)

    \(Solution\) 参考 对于每个点,向唯一有可能与它形成MST的8个点连边,由于是双向单边,所以每个点最多连出4条边(证明见blog) 怎么找到一个区域内最近的点? 只考虑y轴右侧45°的区域 ...

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

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

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

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

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

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

  5. POJ 3241 Object Clustering 曼哈顿最小生成树

    Object Clustering   Description We have N (N ≤ 10000) objects, and wish to classify them into severa ...

  6. [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】

    题目链接:BZOJ - 1016 题目分析 最小生成树的两个性质: 同一个图的最小生成树,满足: 1)同一种权值的边的个数相等 2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性 ...

  7. BZOJ 3732: Network 最小生成树 倍增

    3732: Network 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=3732 Description 给你N个点的无向图 (1 &l ...

  8. [BZOJ]1016 JSOI2008 最小生成树计数

    最小生成树计数 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同 ...

  9. 老oj曼哈顿最小生成树

    Description 平面坐标系xOy内,给定n个顶点V = (x , y).对于顶点u.v,u与v之间的距离d定义为|xu – xv| + |yu – yv| 你的任务就是求出这n个顶点的最小生成 ...

随机推荐

  1. Java——TCP

    import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; //================ ...

  2. QT 初阶 第二章 创建对话框(查找对话框实例)

    最终效果图: 该对话框由三个文件组成:finddialog.h .finddialog.cpp. main.cpp 代码+注释 /*--finddialog.h--*/ #ifndef FINDDIA ...

  3. C#----Get和Set在属性中的使用

    Get和Set在属性中的作用: 第一个作用:保证数据的安全性,对字段进行了有效的保护. 第二个作用:起到监视作用 private int width=0; public int Width { get ...

  4. C# JIT & AOT

    http://msdn.microsoft.com/library/z1zx9t92 http://msdn.microsoft.com/en-us/library/ht8ecch6(v=vs.90) ...

  5. Echarts 页面多图自适应的解决办法 (转)

    项目中用到了echarts的多图表的 问题,如果设置了 window.onresize  = option.chart.resize() 只能控制 某个图表的 自适应,如果要是页面上的图表都要自适应. ...

  6. python 基本数据类型分析

    在python中,一切都是对象!对象由类创建而来,对象所拥有的功能都来自于类.在本节中,我们了解一下python基本数据类型对象具有哪些功能,我们平常是怎么使用的. 对于python,一切事物都是对象 ...

  7. 让FineUI数据绑定支持dynamic对象

    FineUI非常好用,但是有一个缺点,就是不支持dynamic对象的数据绑定.查了一下源代码,找了解决方案,其实只需要几行代码就可以搞定,这就是开源的好处. 本想直接在CodePlex上贡献代码,但不 ...

  8. iOS-马上着手开发iOS应用应用程序-第二部分构建应用程序

    第二部分构建应用程序 1,应用程序开发过程 2,设计用户界面 3,定义交互 4,教程:串联图 1,应用程序开发过程 定义概念 设计用户界面 定义交互 实现行为整合数据 对象是应用程序的基石 类是对象的 ...

  9. yii2-按需加载并管理CSS样式/JS脚本

    原文地址:https://segmentfault.com/a/1190000003742452

  10. MongoDB学习笔记(索引)(转)

    一.索引基础:    MongoDB的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的优化技巧.下面是创建索引的命令:    > db.test.ensureIndex({" ...