社区讨论

100pts求卡常

P6362平面欧几里得最小生成树参与者 4已保存回复 6

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
6 条
当前快照
1 份
快照标识符
@mke3oj70
此快照首次捕获于
2026/01/14 22:12
上个月
此快照最后确认于
2026/01/17 22:15
上个月
查看原帖
不会科技并试图用Boruvka+K-D tree通过次题。
时间复杂度理论O(n* logn * logn)。
最好一次卡成这样,用了随机旋转。
已经卡不动了,有没有大佬有卡常技巧?
CPP
#include<bits/stdc++.h>
#define ll long long
#define pii pair<double,double>
using namespace std;
const int N=1e5+7;
const ll inf=2e18+7;
int n,m,f[N],idx,c[N];
pii p[N];
double ans;
struct node{
	int l,r;
	double x,y;
}t[N];
inline int find(int x){
	if(f[x]==x) return x;
	return f[x]=find(f[x]);
}
inline bool cmp(pii x,pii y){
	if(x.second==y.second) return x.first<y.first;
	return x.second<y.second;
}
inline double dis(int pos,int pos_){
	return (t[pos].x-t[pos_].x)*(t[pos].x-t[pos_].x)+
	(t[pos].y-t[pos_].y)*(t[pos].y-t[pos_].y);
}
inline int init(int l,int r,bool op){
	if(l>r) return 0;
	int mid=l+r>>1,pos=++idx;
	if(op) sort(p+l,p+r+1,cmp);
	else sort(p+l,p+r+1);
	t[pos].x=p[mid].first,t[pos].y=p[mid].second;
	t[pos].l=init(l,mid-1,!op),t[pos].r=init(mid+1,r,!op);
	return pos;
}
inline int upd(int pos){
	if(!pos) return -1;
	int ansl=upd(t[pos].l),ansr=upd(t[pos].r),ans=find(pos);
	if(ansl!=-1) ans=(ans!=ansl?0:ans);
	if(ansr!=-1) ans=(ans!=ansr?0:ans);
	c[pos]=ans;
	return ans;
}
inline void ask(int pos,int k,pii &ans,bool op){
	if(!pos||c[pos]==find(k)) return ;
	if(find(k)!=find(pos)){
		ans=min(ans,{dis(pos,k),(double)(pos)});
	}
	if(!op){
		bool f=t[k].x<=t[pos].x;
		ask(f?t[pos].l:t[pos].r,k,ans,!op);
		if((t[pos].x-t[k].x)*(t[pos].x-t[k].x)<ans.first){
			ask(f?t[pos].r:t[pos].l,k,ans,!op);
		}
	}
	else{
		bool f=t[k].y<=t[pos].y;
		ask(f?t[pos].l:t[pos].r,k,ans,!op);
		if((t[pos].y-t[k].y)*(t[pos].y-t[k].y)<ans.first){
			ask(f?t[pos].r:t[pos].l,k,ans,!op);
		}
	}
}
inline bool merge(int u,int v){
	u=find(u),v=find(v);
	if(u==v) return 0;
	f[u]=v;
	return 1;
}
int main(){
	//freopen("P6362_3.in","r",stdin);
	//freopen("P6362_3.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	double tmp=1919810;
	double sc=sin(tmp),cc=cos(tmp);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>p[i].first>>p[i].second;
		p[i]={p[i].first*cc-p[i].second*sc,
		p[i].first*sc+p[i].second*cc};
		f[i]=i;
	}
	init(1,n,0);
	int cnt=0;
	while(cnt!=n-1){
		upd(1);
		for(int i=1;i<=n;i++){
			p[i]={inf,0};
		}
		for(int i=1;i<=n;i++){
			ask(1,i,p[find(i)],0);
		}
		
		for(int i=1;i<=n;i++){
			if(find(i)!=i||!p[i].second) continue;
			if(merge(p[i].second,i)){
				ans+=sqrt(p[i].first),cnt++;
			}
		}
	}
	cout<<fixed<<setprecision(6)<<ans;
	return 0;
}

回复

6 条回复,欢迎继续交流。

正在加载回复...