題目
教主上電視了,但是蔚藍城郊區沿河的村莊卻因電纜線路老化而在直播的時候停電,這讓市長SP先生相當的憤怒,他決定重修所有電纜,並改日播放錄像,杜絕此類情況再次發生。
河流兩旁各有n,m個村莊,每個村莊可以用二維座標表示,其中河流一旁的村莊橫座標均爲x1,河流另一旁的村莊橫座標均爲x2。由於地勢十分開闊,任意兩個村莊可以沿座標系直線修建一條電纜連接,長度即爲兩村莊的距離。要修建若干條電纜,使得任意兩個村莊都可以通過若干個有電纜連接的村莊相連。
因爲修建的經費與長度成正比,SP市長當然希望所花的錢越少越好,所以他希望你來幫助他設計一套方案,使得電纜總長度最小,並告訴所需要的電纜總長度。
解題思路
同一條直線上的,我們可以相鄰兩兩連邊。
不同的,我們取最近的兩個點進行連邊。
然後跑kruskal最小生成樹就可以了
代碼
#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long
#define rep(i,x,y) for(int i=x;i<=y;i++)
using namespace std;
int n,m,x1,x2,f[1200005],q[600005],b[600005],tot;
double ans;
struct node{int x,y; ll z; }a[2400005];
inline ll cf(int x){return 1ll*x*x;}
inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
inline bool cmp(node x,node y){return x.z<y.z;}
int main(){
scanf("%d%d%d%d",&n,&m,&x1,&x2);
rep(i,1,n) scanf("%d",&q[i]),q[i]+=q[i-1];
rep(i,1,m) scanf("%d",&b[i]),b[i]+=b[i-1];
int r=1;
rep(i,1,n){
while(b[r]<q[i]&&r<=m) r++;
a[++tot]=(node){i,n+r,cf(q[i]-b[r])+cf(x2-x1)};
if (r>1) a[++tot]=(node){i,n+r-1,cf(q[i]-b[r-1])+cf(x2-x1)};
}
rep(i,1,n-1) a[++tot]=(node){i,i+1,cf(q[i]-q[i+1])};
rep(i,1,m-1) a[++tot]=(node){i+n,i+n+1,cf(b[i]-b[i+1])};
rep(i,1,n+m) f[i]=i;
sort(a+1,a+tot+1,cmp);
int cnt=0;
rep(i,1,tot){
int x=find(a[i].x),y=find(a[i].y);
if (x!=y){
f[x]=y;
cnt++;
ans+=sqrt((double)(a[i].z));
}
if (cnt==(n+m-1)) return 0&printf("%.2lf",ans);
}
return 0;
}