E - Expectations sky-high ( 求树的任意两点距离和 )

E - Expectations sky-high ( 求树的任意两点距离和 )

题目链接:https://vjudge.net/problem/Gym-102020E

题意:有一棵n个点的树,问任选两点 ( 不一定不同 ) 的概率长度是多长。

思路:dfs容易求出某个点到其他所有点的距离和是多少。难点在于如何用一次dfs求出所有点到其他所有点的距离和。定义一个点到其所有子节点的距离和为ans,我们先跑一次dfs求出1号节点的ans[ 1 ] ,过程肯定要用到数组sum[ u ]表示以1为根节点时,u到其子节点的距离和为多少,顺便更新一下siz[u]( 表示u的子节点数 )的大小。

重点来了,我们如何根据一个节点的ans[1] 及其相应的sum[],siz[],来处理出所有点的ans来。

           fa

      u           x

 ...     ....         ...

上图的树中,fa是u的父亲节点,我们当前需要求u点的ans值,我们可以O(1) 来求u点的ans值 = u点到其子树的和值sum[u] + fa点到除u外其它子树的ans值, ans[fa]-sum[u]-siz[u]  + u和其父亲的那条连边出现的次数(n-siz[u]).

int siz[maxn],sum[maxn],ans[maxn];
vector G[maxn];
void dfs( int u, int fa )  // 求一个点的ans值,及其sum和siz数组
{
    siz[u] = 1;
    sum[u] = 0;
    for ( int i=0; i

 

这个题是要算概率长度,我们算出总长度来除方案数就好了。

总长度 = ans数组和/2 。 除2是因为对于每一对点都算了两遍

方案数 = n*(n+1)/2 。

这样分子分母可以同乘2方便计算。

代码:

#include 
#define int long long

using namespace std;

const int mod = 1e9+7;
const int maxn = 2e5+10;
vector G[maxn];
int siz[maxn],sum[maxn],ans[maxn];
int n;

int qpow( int a, int n )
{
    int re = 1;
    while ( n ) {
        if ( n&1 ) re=(re*a)%mod;
        a = (a*a)%mod;
        n >>= 1;
    }
    return re;
}

void dfs( int u, int fa )
{
    siz[u] = 1;
    sum[u] = 0;
    for ( int i=0; i> n;
    for ( int i=0; i

 

你可能感兴趣的:(图论补题)