首先要算清对于某一个集合时的最优方案 即在其中间值附近的两个点上 他们做最后一步移动 两个点分别为 a[i]和a[i+1] 则 最后答案为 max(a[i]-small, big-a[i+1])+(a[i]+a[j])/2;
所以如果把集合放在set里 那么我们只要找到(small+big)/2附近的几个点 计算一下即可
对于集合的合并 学习了启发式合并
启发式 即将小的向大的上合并 可以并查集配合 来完成set的合并
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<set>
#include<map>
#include<stack>
#include<queue>
#define INF (1ll<<62)
#define mem(x,y) memset(x,y,sizeof(x))
#define pb push_back
using namespace std;
typedef long long ll;
#define bug puts("===========");
const double pi=(acos(-1.0));
const double eps=1e-8;
const int inf=1e9+10;
const int maxn=300000+5;
const int mod=1e9+7;
/*===============================*/
int n,a,b;
int si[maxn],f[maxn];
set<int>st[maxn];
set<int>:: iterator it,it2;
void init(){
for(int i=1;i<=n;i++){
si[i]=1;
f[i]=i;
st[i].clear();
st[i].insert(i);
}
}
int F(int x){
return f[x]==x?x:f[x]=F(f[x]);
}
inline void work(int a,int b){
f[b]=a; si[a]+=si[b]; si[b]=0;
st[a].insert(st[b].begin(),st[b].end()); st[b].clear();
int l= *(st[a].begin());
it=st[a].end(); it--;
int r= *(it);
int mid=l+r>>1;
it2=it=st[a].lower_bound(mid);
it2++;
double ans=inf;
if(it2!=st[a].end()){
int x=*it,y=*it2;
double z=(x+y)*0.5;
ans=max(z-l,r-z);
}
if(it!=st[a].begin()){
it--; it2--;
int x=*it,y=*it2;
double z=(x+y)*0.5;
ans=min(ans,max(z-l,r-z));
if(it!=st[a].begin()){
it--; it2--;
int x=*it,y=*it2;
double z=(x+y)*0.5;
ans=min(ans,max(z-l,r-z));
}
}
printf("%.1lf\n",ans);
}
int main()
{
int T_T;
scanf("%d",&T_T);
while(T_T--){
scanf("%d",&n);
init();
for(int i=1;i<n;i++){
scanf("%d%d",&a,&b);
a=F(a); b=F(b);
if(si[a]>si[b]) work(a,b);
else work(b,a);
}
}
return 0;
}