【传送门: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 ",ans); return 0; }