codeforces E. Famil Door and Roads 期望

一棵树,n个节点,边长为1,有q个询问,每个询问给出u,v(u != v),问在树上等概率加一条边,如果使得u,v在一个环内,则这种加边方式是合法的,此时的值为环的长度,所有合法的加边方式出现的概率相等,问值的期望。

2 <= n,m <= 10^5

对于u,v原来路径上的边一定在环内,贡献为1,新加的边也一定在环内,贡献为1,求其余的边的贡献就行了

分2种情况考虑:

1.lca(u,v) 不等于u 和 v

2.lca(u,v) 为u 或者 v

代码:

//File Name: cf629E.cpp
  //Created Time: 2017年01月05日 星期四 17时20分29秒

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN = 100000 + 2;
int siz[MAXN],dis[MAXN];
int pa[MAXN][20];
LL f[MAXN],g[MAXN];
vector<int> G[MAXN];
void dfs0(int u,int p){
    siz[u] = 1;
    dis[u] = dis[p] + 1;
    f[u] = 0;
    for(int i=0;i<G[u].size();++i){
        int v = G[u][i];
        if(v == p) continue;
        pa[v][0] = u;
        dfs0(v,u);
        siz[u] += siz[v];
        f[u] += f[v] + siz[v];
    }
}
void dfs1(int u,int p,int n){
    for(int i=0;i<G[u].size();++i){
        int v = G[u][i];
        if(v == p) continue;
        g[v] = n + g[u] - 2 * siz[v];
        dfs1(v,u,n);
    }
}
void cal_pa(int n){
    for(int j=1;(1<<j)<=n;++j){
        for(int i=1;i<=n;++i){
            if(pa[i][j-1] != -1)
                pa[i][j] = pa[pa[i][j-1]][j-1];
        }
    }
}
int cal_lca(int a,int b){
    if(dis[a] < dis[b]) swap(a,b);
    int cnt = 0;
    for(;(1<<cnt)<=dis[a];++cnt);
    --cnt;
    for(int j=cnt;j>=0;--j){
        if(dis[a] - (1<<j) >= dis[b])
            a = pa[a][j];
    }
    if(a == b) return a;
    for(int j=cnt;j>=0;--j){
        if(pa[a][j] != -1 && pa[a][j] != pa[b][j])
            a = pa[a][j],b = pa[b][j];
    }
    return pa[a][0];
}
int cal(int u,int v){
    int cnt = 0;
    for(;(1<<cnt)<=dis[u];++cnt);
    --cnt;
    for(int j=cnt;j>=0;--j){
        if(dis[u] - (1<<j) > dis[v])
            u = pa[u][j];
    }
    return u;
}
void solve(int n,int m){
    memset(pa,-1,sizeof(pa));
    dfs0(1,0);   //dis,siz,in,f,pa[i][0],dep
    g[1] = f[1];
    dfs1(1,0,n);     //g
    cal_pa(n); // pa
    int u,v,lca,w;
    while(m--){
        scanf("%d %d",&u,&v);
        lca = cal_lca(u,v);
        if(lca != u && lca != v){
            int tmp = dis[u] + dis[v] - 2 * dis[lca] + 1;
            double ans = tmp + (f[u] + 0.0) / siz[u] + (f[v] + 0.0) / siz[v];
            printf("%.15f\n",ans);
        }
        else{
            if(lca == u) swap(u,v);
            w = cal(u,v);
            if(pa[w][0] != v){
                printf("-1");
                return ;
            }
            int tmp = dis[u] - dis[v] + 1;
            double ans = tmp + (f[u] + 0.0) / siz[u] + (g[v] - f[w] - siz[w] + 0.0) / (n - siz[w]);
            printf("%.15f\n",ans);
        }
    }
}
int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1,u,v;i<n;++i){
        scanf("%d %d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    solve(n,m);
    return 0;
}
时间: 2024-10-09 22:42:52

codeforces E. Famil Door and Roads 期望的相关文章

Codeforces 629 E. Famil Door and Roads

题目链接:http://codeforces.com/problemset/problem/629/E 询问这个简单环的期望.考虑将这个环拆成两部分. 令${deep[x]>=deep[y]}$,${size[x]}$表示以$x$为根的子树大小,${sdown[x]}$示以$x$为根的子树的所有节点到$x$的距离和,${sall[x]}$所有点到$x$的距离和.${ne}$表示从${y-->x}$路径上${y}$的儿子. 1.${dis(x,y)}$这是一个环肯定要经过的,算入答案. 2.分情

codeforces 629C Famil Door and Brackets (dp + 枚举)

题目链接: codeforces 629C Famil Door and Brackets 题目描述: 给出完整的括号序列长度n,现在给出一个序列s长度为m.枚举串p,q,使得p+s+q是合法的括号串,长度为n,问p,q的取值数目. 解题思路: 枚举p的长度,可以直接得到q的长度.因为要满足在任意位置'(' 数目大于 ’)‘ 的数目,所以统计一下s串中 ’(‘ - ')' 的最小数目minx.dp[i][j] 代表 到位置 i 时,满足 '(' - ')' == j 的情况数目.然后枚举p的 j

Codeforces Round #259(div2)C(数学期望)

数学题. 关键是求最大值为k时有多少种情况,结果是kn-(k-1)n-1.可以这么想:每一次都从1至k里选,共kn种,这里需要再减去每一次都从1至k-1里面选的情况.当然也可以分类计数法:按出现几次k来分类,然后逆着用一下二项式定理得出结论. 整个的期望是Σk(kn-(k-1)n-1)/mn,其中k=1......n. 这里的技巧在于:由于n<=105,   kn显然会RE,那么就先把分母除上,每次算一个小于1的浮点数的n次方,肯定不会RE.C++中乘方用pow函数算是很快的. #include

Codeforces 123E Maze(树形DP+期望)

[题目链接] http://codeforces.com/problemset/problem/123/E [题目大意] 给出一棵,给出从每个点出发的概率和以每个点为终点的概率,求出每次按照dfs序从起点到达终点的期望. [题解] 首先对于期望计算有X(x,y)=X(x)*X(y),所以对于每次dfs寻路只要求出其起点到终点的期望步数,乘上起点的概率和终点的概率即可.对于一个固定起点和终点的dfs寻路,我们可以发现如果一个点在必要路径上,那么这条路被走过的期望一定为1,如果不在必要路线上,那么走

【CodeForces 567E】President and Roads(最短路)

Description Berland has n cities, the capital is located in city s, and the historic home town of the President is in city t (s ≠ t). The cities are connected by one-way roads, the travel time for each of the road is a positive integer. Once a year t

Codeforces 362D Fools and Foolproof Roads 构造题

题目链接:点击打开链接 题意: 给定n个点 m条边的无向图 须要在图里添加p条边 使得图最后连通分量数为q 问是否可行,不可行输出NO 可行输出YES,并输出加入的p条边. set走起.. #include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<vector> #include<set> using namespace s

CodeForces 629C Famil Door and Brackets

DP.听了同学的讲解才会的. 具体做法:dp[i][j]表示长度为 i 的括号串,前缀和(左括号表示1,右括号表示-1)为 j 的有几种. 状态转移很容易得到:dp[i][j]=dp[i - 1][j + 1]+dp[i - 1][j - 1],表示 i 这位分别放上右括号和左括号. 然后就是要处理题目的问题了: 我们可以枚举P串的长度和P串的前缀和,来看这种情况下是否符合题目要求,如果符合答案增加. 那么如何判断P串长度为left,前缀和为p的情况下,有几种符合题目要求呢? 先对已经存在的那个

Codeforces 191 C Fools and Roads (树链剖分)

题目链接~~> 做题感悟:这题在做了HDU 5044后就感觉很简单了. 解题思路: 先树链剖分一下,把树剖分成链,因为最后全是询问,so~可以线性操作.经过树链剖分后,就会形成许多链,但是每条边都有编号,相当于一个数组进行线性操作,这样,如果在 u  ~ v 去都增加 1 ,那么可以让 sum [ u ] += 1 ; sum [ v + 1 ] -= 1 ; 这里假设 v 的编号大.最后的时候只要从后往前遍历一次就可以了,得到所有的结果.明白这点后再加上树链剖分的思想就可以解决了. 代码: #

codeforces 567 E. President and Roads 【 最短路 桥 】

给出一个有向图,从起点走到终点(必须走最短路),问一条边是否一定会被经过,如果不经过它,可以减小它的多少边权使得经过它(边权不能减少到0) 正反向建图,分别求出起点到每个点的最短距离,终点到每个点的最短距离(用这个可以算出减小的边权) 再将在最短路径上的边重新建图.求出里面的桥,就是必须经过的边 wa了一上午------呜呜呜呜 先wa 19  是因为求桥的时候是无向图,数组开小了一半 然后 wa 46 ,是因为dis[]数组初始化为 1 << 30 -1 ,应该再开大点 ,开成 1 <