codeforces 500D New Year Santa Network

题意:求出在一棵树中随机找三个点,三点中任意两点路径长度之和的期望。

任意一条边都会将这棵树分成两部分,这样可以计算每条边的期望。

#include <cstdio>
#include <cstring>
#define maxn 100100
#define ll long long
double ans,tot;
struct edge
{
    int u,v,id,next;
}e[maxn*2];
ll len[maxn],son[maxn];
int head[maxn],cnt,s[maxn],t[maxn];
int n,m;

void add(int u,int v,int id)
{
    e[cnt].u=u;
    e[cnt].v=v;
    e[cnt].id=id;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
int dfs(int u,int fa)
{
    son[u]=1;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].v;
        int id=e[i].id;
        if(v==fa) continue;
        son[u]+=dfs(v,u);
        if(son[v]>=2) ans = ans +  2 * len[id] * (son[v] * (son[v] - 1) / 2) * (n - son[v]) * 1.0 / tot;
        if(n-son[v]>=2) ans = ans + 2 * len[id] * ((n - son[v]) * (n - son[v] - 1) / 2) * son[v] * 1.0 / tot;
    }
    return son[u];
}
int main()
{
    scanf("%d",&n);
    memset(head,-1,sizeof(head));
    cnt=0;
    for(int i=1;i<n;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        s[i]=u;
        t[i]=v;
        len[i]=w;
        add(u,v,i);
        add(v,u,i);
    }
    ans=0;
    tot=1.0*n*(n-1)*(n-2)/6;
    dfs(1,-1);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int id,w,v;
        scanf("%d%d",&id,&w);
        if(son[s[id]] > son[t[id]]) v = t[id];
        else v=s[id];
        if(son[v]>=2) ans = ans -  2 * (len[id] - w) * (son[v] * (son[v] - 1) / 2) * (n - son[v]) * 1.0 / tot;
        if(n-son[v]>=2) ans = ans - 2 * (len[id] - w) * ((n - son[v]) * (n - son[v] - 1) / 2) * son[v] * 1.0 / tot;
        len[id]=w;
        printf("%.8lf\n",ans);
    }
    return 0;
}


 

你可能感兴趣的:(codeforces 500D New Year Santa Network)