题解

Boruvka算法:每个点都先找到离自己最近/最远的点,把这些边连上,再把形成的连通块看成点继续操作

显然这样做每次连通块数目至少会减半

问题就在于怎样快速求一个块到块外点的距离

我们可以把绝对值展开出4中情况

每种情况中,对于每一个点,把它对绝对值之和的贡献放到set里面(开4个set,存同一个点的4种贡献)

然后求一个块的最远点时,就把该连通块所有点的所有贡献从4个set里面全部删掉

查询就分4类讨论,每次都要找与自己相反的坐标贡献(因为绝对值的4种情况中,两个点的横纵坐标总是相减)

求完了之后再把点加回set

启发式合并,就是指把size小的合并到size大了里面,这样,下一次的合并代价至少会*2,空间开销与耗时会更小

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 100005
#define mp(x,y) make_pair(x,y)
int a[N][2],b[N][4];
set<pair<int,int> > S[4];
set<pair<int,int> >::iterator it;
int tmp[N][3],cnt,fa[N];
bool vis[N];
vector<int> id[N];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main()
{
	freopen("mst.in","r",stdin);
	freopen("mst.out","w",stdout);
	int n,i,j,k,u,ff,p,q;
	n=gi();
	for(i=1;i<=n;i++){
		a[i][0]=gi();a[i][1]=gi();
		fa[i]=i;id[i].push_back(i);
		b[i][0]=a[i][0]+a[i][1];S[0].insert(mp(b[i][0],i));
		b[i][1]=a[i][1]-a[i][0];S[1].insert(mp(b[i][1],i));
		b[i][2]=a[i][0]-a[i][1];S[2].insert(mp(b[i][2],i));
		b[i][3]=-a[i][0]-a[i][1];S[3].insert(mp(b[i][3],i));
	}
	long long ans=0;
	while(1){
		memset(vis,0,sizeof(vis));
		cnt=0;
		for(i=1;i<=n;i++){
			ff=find(i);
			if(id[ff].size()==n){
				printf("%lld",ans);
				return 0;
			}
			if(vis[ff])continue;
			vis[ff]=1;
			for(j=0;j<id[ff].size();j++)
				for(k=0,u=id[ff][j];k<=3;k++)
					S[k].erase(mp(b[u][k],u));
			int mx=-1,pos=0;
			for(j=0;j<id[ff].size();j++)
				for(k=0,u=id[ff][j];k<=3;k++){
					it=S[k^3].end();it--;
					if((it->first+b[u][k])>mx){
						mx=it->first+b[u][k];
						pos=it->second;
					}
				}
			for(j=0;j<id[ff].size();j++)
				for(k=0,u=id[ff][j];k<=3;k++)
					S[k].insert(mp(b[u][k],u));
			
			tmp[++cnt][0]=mx;tmp[cnt][1]=ff;tmp[cnt][2]=pos;
		}
		for(i=1;i<=cnt;i++){
			p=find(tmp[i][1]);
			q=find(tmp[i][2]);
			if(p==q)continue;
			if(id[p].size()<id[q].size())
				swap(p,q);
			for(j=0;j<id[q].size();j++)
				id[p].push_back(id[q][j]);
			fa[q]=p;ans+=tmp[i][0];
			//printf("%d\n",tmp[i][0]);
		}
	}
}