POJ 3241 曼哈顿最小生成树
感觉讲解,写的非常详细,http://blog.csdn.net/huzecong/article/details/8576908
重点是一个定理: Hint For the graph on the right, there exists a minimum spanning tree in which there is at most one vertex connected with A in the shadow area. You can extend this property to solve the problem.
#include<cstdio> #include<algorithm> #define N 100010 #define INF 0x3f3f3f3f using namespace std; struct point { int x,y,id; bool operator<(const point &p) const { return x==p.x?y<p.y:x<p.x;} }p[N]; struct edge { int a,b,w; bool operator<(const edge &x) const { return w<x.w;} }e[N<<2]; struct BIT { int w,p; }bit[N]; int n,k,m,tot,ans; int f[N],a[N],b[N]; int abs(int x) { return x<0?-x:x; } int find(int x) { return x==f[x]?x:f[x]=find(f[x]); } int query(int x) { int r=INF,p=-1; while(x<=m) { if (bit[x].w<r) r=bit[x].w,p=bit[x].p; x+=x&-x; } return p; } void update(int x, int w, int p) { while(x>0) { if (bit[x].w>w) bit[x].w=w,bit[x].p=p; x-=x&-x; } } void addedge(int a, int b, int w) { ++tot; e[tot].a=a,e[tot].b=b,e[tot].w=w; } int dist(point a, point b) { return abs(a.x-b.x)+abs(a.y-b.y); } int main() { while(scanf("%d%d",&n,&k)!=EOF) { tot=0; for (int i=1;i<=n;i++) { scanf("%d%d",&p[i].x,&p[i].y); p[i].id=i; } for (int dir=1;dir<=4;dir++) { if (dir==2||dir==4) for (int i=1;i<=n;i++) swap(p[i].x,p[i].y); else if (dir==3) for (int i=1;i<=n;i++) p[i].x=-p[i].x; sort(p+1,p+n+1); for (int i=1;i<=n;i++) a[i]=b[i]=p[i].y-p[i].x; sort(b+1,b+1+n); m=unique(b+1,b+1+n)-b-1; for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+m+1,a[i])-b; for (int i=1;i<=m;i++) bit[i].w=INF,bit[i].p=-1; for (int i=n;i>=1;i--) { int pos=query(a[i]); if (pos!=-1) addedge(p[i].id,p[pos].id,dist(p[i],p[pos])); update(a[i],p[i].x+p[i].y,i); } } sort(e+1,e+tot+1); for (int i=1;i<=n;i++) f[i]=i; for (int i=1,ec=n;ec>k&&i<=tot;i++) if (find(e[i].a)!=find(e[i].b)) { f[find(e[i].a)]=find(e[i].b); if (--ec==k) ans=e[i].w; } printf("%d\n",ans); } return 0; }