HDU 5604/BC 67E merge

6 篇文章 0 订阅
1 篇文章 0 订阅

首先要算清对于某一个集合时的最优方案 即在其中间值附近的两个点上 他们做最后一步移动 两个点分别为 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值