zoukankan      html  css  js  c++  java
  • Codeforces Round #411 (Div. 1) D. Expected diameter of a tree

    题目大意:给出一个森林,每次询问给出u,v,问从u所在连通块中随机选出一个点与v所在连通块中随机选出一个点相连,连出的树的直径期望(不是树输出-1)。(n,q<=10^5)

    解法:预处理出各连通块的直径和各点到连通块内一点的最远距离d[x](树形dp+换根),询问若在同一块内输出-1,否则若随机选出两点x,y,直径为max(d[x]+d[y]+1,x所在块直径,y所在块直径),我们把同一连通块内的d排序,枚举小的连通块中的d,到大的连通块中二分d[x]+d[y]+1<=max(x所在块直径,y所在块直径)(或者记下大的块中每种权值出现次数,从max直径开始d[x]递增d[y]递减,复杂度少一个log并仍然只与小的块的大小相关),记忆下相同询问,这样我们枚举小的次数最大只有$O(n^{1.5})$(每次我们复杂度只跟小的有关,那么最劣情况只有每次两个块大小相等,假设所有联通块大小均为k,我们的复杂度是$O(k*min(q,(frac{n}{k})^2))$,容易证明复杂度最大是$O(n^{1.5})$)。

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<map>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 100000
    #define p(x,y) make_pair(x,y)
    struct edge{int nx,t;}e[MN*2+5];
    int f[MN+5],h[MN+5],en,d[MN+5],d2[MN+5],mx[MN+5];
    vector<double> v[MN+5];
    map<pair<int,int>,double> mp;
    int gf(int k){return f[k]?f[k]=gf(f[k]):k;}
    inline void ins(int x,int y)
    {
        e[++en]=(edge){h[x],y};h[x]=en;
        e[++en]=(edge){h[y],x};h[y]=en;
    }
    void upd(int x,int y)
    {
        if(y>d[x])d2[x]=d[x],d[x]=y;
        else if(y>d2[x])d2[x]=y;
    }
    void dp(int x,int fa)
    {
        for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa)
            dp(e[i].t,x),upd(x,d[e[i].t]+1);
        mx[gf(x)]=max(mx[gf(x)],d[x]+d2[x]);
    }
    void dfs(int x,int fa)
    {
        v[gf(x)].push_back(d[x]);
        for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa)
            upd(e[i].t,d[e[i].t]+1==d[x]?d2[x]+1:d[x]+1),dfs(e[i].t,x);
    }
    int main()
    {
        int n,m,q,x,y,i,j,l,r,mid,res;double ans;
        n=read();m=read();q=read();
        while(m--)ins(x=read(),y=read()),f[gf(x)]=gf(y);
        for(i=1;i<=n;++i)if(gf(i)==i)
        {
            dp(i,i);dfs(i,i);v[i].push_back(0);
            sort(v[i].begin(),v[i].end());
            for(j=1;j<v[i].size();++j)v[i][j]+=v[i][j-1];
        }
        while(q--)
        {
            if((x=gf(read()))==(y=gf(read()))){puts("-1");continue;}
            if(x>y)swap(x,y);
            if(mp[p(x,y)]){printf("%.10lf
    ",mp[p(x,y)]);continue;}
            if(v[x].size()>v[y].size())swap(x,y);
            for(i=1,ans=0;i<v[x].size();++i)
            {
                for(l=1,r=v[y].size()-1,res=0;l<=r;)
                {
                    mid=l+r>>1;
                    if(v[x][i]-v[x][i-1]+v[y][mid]-v[y][mid-1]+1<=max(mx[x],mx[y]))
                        res=mid,l=mid+1;
                    else r=mid-1;
                }
                ans+=(double)res*max(mx[x],mx[y])+
                     (v[y].size()-1-res)*(v[x][i]-v[x][i-1]+1)+v[y][v[y].size()-1]-v[y][res];
            }
            if(x>y)swap(x,y);
            printf("%.10lf
    ",mp[p(x,y)]=ans/(v[x].size()-1)/(v[y].size()-1));
        }
    }
  • 相关阅读:
    最好的在线打字练习网站
    input 的 type 等于 file
    windows 删除文件或文件夹
    nvm 管理 node 版本
    github 的 fork 取消功能
    window cmd 命令行下创建文件夹和文件
    17_10_11 Redis 指令
    17_10_11 Mac 上的brew 安装指令
    17_10_11 运算符&,&&,>> 和 >>>
    17_10_10 乱码问题总结
  • 原文地址:https://www.cnblogs.com/ditoly/p/CF411.html
Copyright © 2011-2022 走看看