[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\n",(double)ans/fm);
    }
}
View Code

 

 

posted @ 2019-03-21 21:44  Vagari  阅读(154)  评论(0编辑  收藏  举报