题解 CF500D 【New Year Santa Network】

题目链接

这道题首先是要看看该如何化简,先把三元组化成二元组。

之后统计经过某条边的 次数$*$权值  的和。

最后除以总基数 $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;
}

猜你喜欢

转载自www.cnblogs.com/cn-suqingnian/p/9180220.html