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