题解
先存图,再dfs,dfs的过程中统计以x点为子树的点的总数cnt[x],这样可以求出来x和fa[x]连的这条边一共被使用了(n-cnt[x])*cnt[x]次
再求出来最短路之和tot(因为是树,所以最短路好求),对于每次修改,只需要将将差乘上使用次数就好了
#include<iostream>
#include<cstdio>
using namespace std;
long long x,n,y,fa[1000001],m,e,head[1000001],cnt[100001],dis[100001];
long long tot;
struct node{long long from,to,cost,nxt;}a[1000001];
void add(long long f,long long t,long long w)
{
e++;
a[e].to=t;
a[e].from=f;
a[e].cost=w;
a[e].nxt=head[f];
head[f]=e;
}
void dfs(long long x)
{
for(long long i=head[x];i;i=a[i].nxt)
{
long long t=a[i].to;
if(t!=fa[x])
{
dfs(t);
cnt[x]+=cnt[t];
tot+=(n-cnt[t])*cnt[t]*a[i].cost;
}
}
cnt[x]++;
}
int main()
{
// freopen("1.txt","r",stdin);
cin>>n;fa[1]=1;
for(long long i=1;i<=n-1;i++)
{
scanf("%lld%lld",&x,&dis[i+1]);
fa[i+1]=x;
add(i+1,x,dis[i+1]);
add(x,i+1,dis[i+1]);
}
dfs(1);
printf("%lld\n",tot);
cin>>m;
for(long long i=1;i<=m;i++)
{
scanf("%lld%lld",&x,&y);
tot+=(y-dis[x])*cnt[x]*(n-cnt[x]);
dis[x]=y;
printf("%lld\n",tot);
}
}
吧啦吧啦吧啦吧啦吧啦吧啦吧啦吧啦吧啦