题意:求出在一棵树中随机找三个点,三点中任意两点路径长度之和的期望。
任意一条边都会将这棵树分成两部分,这样可以计算每条边的期望。
#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;
}