• [LCA][数学]JZOJ 4794 富爷说是一棵树


    Description

    富爷说来一棵树,于是大头栽了一棵树。树大了,有n个点和n - 1条边,任意两个点都是联通的,点的标号为1 - n。爱树的大头和富爷在树上安居乐业,但大头住在u,而富爷住在v,他们都很不高兴,因为u到v有且只有一条简单路径。
    当然了,树王富爷找到了解决办法,他打算带着大头再给树建一条边(保证不是自环),而且他们会在n * (n - 1) / 2的方案中随机选择一种。
    但,要让富爷和大头开心是有条件的。只有新建边之后,富爷去大头家以及大头去富爷家存在两条路径不会走相同的边时,他们才会呵呵(也就是说 存在一个简单环包含u和v)。
    不开心的事情选择忘记。当富爷和大头开心时,你能得到愉快值等于环的大小。所以,你要告诉富爷和大头,当他们开心时(只考虑在环内),他们的期望愉悦值。
     

    Input

    第 1 行包含 2个正整数n 和 m (2≤n,m≤100000),表示树有n 个点,以及有m组询问。
    接下来n−1行描述了一些双联通边,每行包含两个整数ai和bi,(1≤ai,bi≤n),表示第i条路连接的两个点。
    最后m行描述富爷和大头,第i行包含两个整数ui和vi,(1≤ui,vi≤n,ui≠vi),表示富爷和大头分别住在哪里。

    Output

    对于每组询问你需要输出如果富爷和大头开心的期望愉快度。你的答案与标准答案误差不能超过1e-6。
     

    Sample Input

    输入1:
    4 3
    2 4
    4 1
    3 2
    3 1
    2 3
    4 1
    输入2:
    3 3
    1 2
    1 3
    1 2
    1 3
    2 3

    Sample Output

    输出1:
    4.00000000
    3.00000000
    3.00000000
    输出2:
    2.50000000
    2.50000000
    3.00000000
    【输入输出样例 2 说明】
    1、(1,2)和(2,3)均能让富爷和大头开心,则期望愉悦值为(2 + 3)/ 2 = 2.5
    2、(1,3)和(2,3)均能让富爷和大头开心,则期望愉悦值为(2 + 3)/ 2 = 2.5
    3、(2,3)能使富爷和大头开心,则期望愉悦值为3
     
     

    Data Constraint

    20% n,m <= 2000
    40% n,m <= 10^5 树是随机的
    60% n,m <= 10^5 每个点的度数均为2
    100% n,m <= 10^5

     分析

    题意大概就是树上加一条边使一对点在一个简单环中的期望环长

    我们发现,其实答案就是dist(u,v)*size[u]*size[v]+f[u]*size[v]+f[v]*size[u]

    dist就是u到v的路径长度,size是子树大小,f是子树内所有点到子树的根的距离和

    分母也显然是size[u]*size[v]

    然后我们发现size和f都是可以预处理的,dist可以直接得出

    然后如果u,v有祖孙关系的话,子树就不是往常意义的子树(假设v是祖先),那就是除了有u的那棵子树以外的都是v的子树

    所以要处理一个g[v]来搞这种情况

     
    #include <iostream> 
    #include <cstdio>
    #include <memory.h>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=1e5+10;
    struct Edge {
        int v,nx;
    }e[2*N];
    int cnt,list[N];
    int fa[N][20],dep[N];
    ll f[N],g[N],sz[N];
    int n,m,logn;
    
    void Add(int u,int v) {
        e[++cnt]=(Edge){v,list[u]};list[u]=cnt;
        e[++cnt]=(Edge){u,list[v]};list[v]=cnt;
    }
    
    void DFS(int u,int fat) {
        fa[u][0]=fat;dep[u]=dep[fat]+1;sz[u]=1;
        for (int i=list[u];i;i=e[i].nx)
            if (e[i].v!=fat) {
                DFS(e[i].v,u);
                sz[u]+=sz[e[i].v];
                f[u]+=f[e[i].v]+sz[e[i].v];
            }
    }
    
    void DFS_G(int u,int fa) {
        if (fa) g[u]=f[fa]-f[u]-sz[u]+g[fa]+(n-sz[fa]);
        for (int i=list[u];i;i=e[i].nx)
            if (e[i].v!=fa) DFS_G(e[i].v,u);
    }
    
    int LCA(int u,int v) {
        for (int i=logn;i>=0;i--) if (dep[fa[u][i]]>=dep[v]) u=fa[u][i];
        if (u==v) return v;
        for (int i=logn;i>=0;i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
        return fa[u][0];
    }
    
    int Witch_Son(int u,int v) {
        for (int i=logn;i>=0;i--) if (dep[fa[u][i]]>dep[v]) u=fa[u][i];
        return u;
    }
    
    int main() {
        scanf("%d%d",&n,&m);
        for (int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),Add(u,v);
        DFS(1,0);
        DFS_G(1,0);
        logn=log(n)/log(2);
        for (int i=1;i<=logn;i++) 
            for (int j=1;j<=n;j++) fa[j][i]=fa[fa[j][i-1]][i-1];
        for (int i=1;i<=m;i++) {
            int u,v,lca,son;
            double ans=0,fm=0;
            scanf("%d%d",&u,&v);
            if (dep[u]<dep[v]) swap(u,v);
            lca=LCA(u,v);
            if (lca==v) {
                son=Witch_Son(u,v);
                ans=(double)(dep[u]-dep[v]+1)*sz[u]*(n-sz[son])+g[son]*sz[u]+f[u]*(n-sz[son]);
                fm=sz[u]*(n-sz[son]);
            }
            else {
                ans=(double)(dep[u]+dep[v]-2*dep[lca]+1)*sz[u]*sz[v]+f[u]*sz[v]+f[v]*sz[u];
                fm=sz[u]*sz[v];
            }
            printf("%lf
    ",(double)ans/fm);
        }
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    HUD 1284 钱币兑换问题
    HUD 1284 钱币兑换问题
    HDU 1283 最简单的计算机
    HDU 1283 最简单的计算机
    商品搜索引擎---推荐系统设计
    Spark机器学习:TF-IDF实例讲解
    【读书笔记】Elasticsearch集成Hadoop最佳实践
    Java面试题集合
    Spring Boot企业微信点餐系统-第一章-课程介绍
    Eclipse下svn的创建分支/合并/切换使用
  • 原文地址:https://www.cnblogs.com/mastervan/p/10574864.html
Copyright © 2020-2023  润新知