这道题首先是要看看该如何化简,先把三元组化成二元组。
之后统计经过某条边的 次数$*$权值 的和。
最后除以总基数 $tot$
其中,每条边被计算的次数为 子树的点数$*$非子树的点数 (自己想想)
然后就没了。
ps:一定要注意$n$个节点的树有$n-1$条边,本宝宝调了一下午+一晚上。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct data{int v;int value;int nxt;}edge[200010];
int alist[100010];int cnt;
void add(int u,int v,int value)
{
edge[++cnt].nxt=alist[u];
edge[cnt].v=v;
edge[cnt].value=value;
alist[u]=cnt;
}
int len[100010];
int num[100010];
int n,m;
int in[100010];int out[100010];
double ans;double tot;
void dfs(int x,int f)
{
num[x]=1;
for(int i=alist[x];i!=-1;i=edge[i].nxt)
{
int v=edge[i].v;
if(v==f) continue;
dfs(v,x);
num[x]+=num[v];
ans+=(double)edge[i].value*num[v]*(n-num[v])/tot;
}
}
int u,v,value;
int main()
{
scanf("%d",&n);
memset(alist,-1,sizeof(alist));
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&value);
in[i]=u;
out[i]=v;
len[i]=value;
add(u,v,value);
add(v,u,value);
}
tot=(double)n*(n-1)/6.0;
dfs(1,-1);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
value=min(num[in[u]],num[out[u]]);
ans-=(double)(len[u]-v)*value*(n-value)/tot;
len[u]=v;
printf("%.8lf\n",ans);
}
return 0;
}