51nod-1213: 二维曼哈顿距离最小生成树

【传送门:51nod-1213


简要题意:

  给出平面直角坐标系中的n个点,求出这n个点的曼哈顿距离构成的完全图的最小生成树的大小


题解:

  曼哈顿距离最小生成树的证明

  实际上有影响的边远远小于n2,在处理边的时候用树状数组维护就好了

  最后对得到的边做kruscal就行了


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
struct sit
{
    int x,y,t;
}S[51000],P[51000];
bool cmpx(sit n1,sit n2){return n1.x==n2.x?n1.y>n2.y:n1.x>n2.x;}
struct LS
{
    int x,z,id;
}A[51000];int z;
bool cmp1(LS n1,LS n2){return n1.x<n2.x;}
bool cmp2(LS n1,LS n2){return n1.id<n2.id;}
int n;
void ls()
{
    for(int i=1;i<=n;i++) A[i].x=P[i].x-P[i].y,A[i].id=i;
    sort(A+1,A+n+1,cmp1);
    z=1;A[1].z=1;
    for(int i=2;i<=n;i++)
    {
        if(A[i].x!=A[i-1].x) z++;
        A[i].z=z;
    }
    sort(A+1,A+n+1,cmp2);
}
int a[51000],p[51000];
int lowbit(int x){return x&-x;}
void change(int x,int d,int pos)
{
    while(x<=z)
    {
        if(a[x]>d) a[x]=d,p[x]=pos;
        x+=lowbit(x);
    }
}
int getmin(int x)
{
    int ans=a[0],t=-1;
    while(x!=0)
    {
        if(a[x]<ans) ans=a[x],t=p[x];
        x-=lowbit(x);
    }
    return t;
}
int dis(sit n1,sit n2){return abs(n1.x-n2.x)+abs(n1.y-n2.y);}
struct edge
{
    int x,y,d;
}e[210000];
bool cmpd(edge n1,edge n2){return n1.d<n2.d;}
int fa[51000];
int findfa(int x)
{
    if(fa[x]!=x) fa[x]=findfa(fa[x]);
    return fa[x];
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&S[i].x,&S[i].y);
        P[i]=S[i];
        P[i].t=i;
    }
    int len=0;
    for(int i=1;i<=4;i++)
    {
        if(i==2||i==4) for(int i=1;i<=n;i++) swap(P[i].x,P[i].y);
        else if(i==3) for(int i=1;i<=n;i++) P[i].x=-P[i].x;
        sort(P+1,P+n+1,cmpx);
        ls();
        memset(a,63,sizeof(a));
        for(int i=1;i<=n;i++)
        {
            int t=getmin(A[i].z);
            change(A[i].z,P[i].x+P[i].y,P[i].t);
            if(t==-1) continue;
            else
            {
                int x=P[i].t,y=t;
                e[++len]=(edge){x,y,dis(S[x],S[y])};
            }
        }
    }
    sort(e+1,e+len+1,cmpd);
    LL ans=0;
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=len;i++)
    {
        int fx=findfa(e[i].x),fy=findfa(e[i].y);
        if(fx!=fy)
        {
            fa[fx]=fy;
            ans+=e[i].d;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-10-18 09:23  Star_Feel  阅读(218)  评论(0编辑  收藏  举报