因为是二维平面图,所以点很多,如果全部点都连边,将有N*(N+1)/2条边,数组肯定存不下,所以要想办法减少边数。题目要求的是最小生成树的权值,又是曼哈顿距离,可以发现,对于平面上的某个点,以该点为原点建立直角坐标系,则我们只需要连接四个象限中每个象限离它最近的那个点即可,所以边的数量减少到4*N。
对于每个点,用树状数组维护每个象限离它的最近的那个点的权值就好了
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#define FIN freopen("input.txt","r",stdin);
//#define FOUT freopen("output.txt","w+",stdout);
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps=1e-8;
const double Pi=acos(-1.0);
const int N=50010;
struct point
{
int x,y,id;
bool operator<(const point p)const
{
return x!=p.x?xstruct BIT
{
int min_val,pos;
void init()
{
min_val=INF;
pos=-1;
}
} bit[N];
int par[N];//并查集中父亲
int hight[N];//并查集树的高度
struct edge
{
int u,v,cost;
};
edge G[N<<2];//边集(边数)
int V,E;//顶点数和边数
int get_Manhadm_dis(point a,point b)
{
return abs(a.x-b.x)+abs(a.y-b.y);
}
void addedge(int u,int v,int w)
{
G[E].u=u;
G[E].v=v;
G[E++].cost=w;
}
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int val,int pos)
{
for(int i=x; i>=1; i-=lowbit(i))
if(valint ask(int x,int m)
{
int min_val=INF;
int pos=-1;
for(int i=x; i<=m; i+=lowbit(i))
if(bit[i].min_valreturn pos;
}
void make_edge()
{
int a[N],b[N];
for(int dir=0; dir<4; dir++)
{
if(dir==1||dir==3)
for(int i=0; ielse if(dir==2)
for(int i=0; ifor(int i=0; iint m=unique(b,b+V)-b;
for(int i=1; i<=m; i++)
bit[i].init();
for(int i=V-1;i>=0; i--)
{
int pos=lower_bound(b,b+m,a[i])-b+1;
int ans=ask(pos,m);
if(ans!=-1)
addedge(p[i].id,p[ans].id,get_Manhadm_dis(p[i],p[ans]));
update(pos,p[i].x+p[i].y,i);
}
}
}
//并查集初始化
void Init_union_find(int n)
{
for(int i=0; i0;
}
}
//查询树的根
int find(int x)
{
if(par[x]==x)
return x;
else
return par[x]=find(par[x]);
}
//合并x和y所属的集合
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y)
return ;
if(hight[x]else
{
par[y]=x;
if(hight[x]==hight[y])
hight[x]++;
}
}
//判断x和y是否属于同一个集合
bool same(int x,int y)
{
return find(x)==find(y);
}
bool cmp(const edge& a,const edge& b)
{
return a.costint kruskal()
{
sort(G,G+E,cmp);//按照edge.cost的顺序从小到大排列
Init_union_find(V);//并查集初始化
int ans=0;
for(int i=0; iif(!same(e.u,e.v))
{
unite(e.u,e.v);
ans+=e.cost;
}
}
return ans;
}
int main()
{
scanf("%d",&V);
for(int i=0; iscanf("%d %d",&p[i].x,&p[i].y);
p[i].id=i+1;
}
E=0;
make_edge();
printf("%d\n",kruskal());
}