题意:

给定一颗有N个节点的带权树,之后进行M次操作:

Q操作:询问树上所有点对之间的距离之和

E操作:修改树上某一条边的权值

思路:

树形dp求出每条边被利用的次数并统计

然后修改的时候就把这个边权修改并将改变值乘上利用次数更改ans

/* ***********************************************
Author        :devil
************************************************ */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <stdlib.h>
#define inf 0x3f3f3f3f
#define LL long long
#define rep(a,b) for(int i=a;i<b;i++)
#define dec(a,b) for(int i=a;i>=b;i--)
#define ou(a) printf("%d\n",a)
#define pb push_back
#define mkp make_pair
template<class T>inline void rd(T &x){char c=getchar();x=0;while(!isdigit(c))c=getchar();while(isdigit(c)){x=x*10+c-'0';c=getchar();}}
#define IN freopen("in.txt","r",stdin);
#define OUT freopen("out.txt","w",stdout);
using namespace std;
const int mod=1e9+7;
const int N=1e5+10;
int n,m,x,y,w,sum[N],val[N],level[N];
LL ans;
char s[10];
vector<pair<int,int> >eg[N];
void dfs(int u,int lev,int pre)
{
    sum[u]=1;
    level[u]=lev;
    rep(0,eg[u].size())
    {
        int v=eg[u][i].first;
        if(v==pre) continue;
        val[v]=eg[u][i].second;
        dfs(v,lev+1,u);
        sum[u]+=sum[v];
        ans+=(LL)val[v]*sum[v]*(n-sum[v]);
    }
}
int main()
{
    //IN
    rd(n);rd(m);
    rep(1,n)
    {
        rd(x),rd(y),rd(w);
        eg[x].pb(mkp(y,w));
        eg[y].pb(mkp(x,w));
    }
    dfs(1,1,1);
    while(m--)
    {
        scanf("%s",s);
        if(s[0]=='Q') printf("%lld\n",ans);
        else
        {
            rd(x),rd(y),rd(w);
            if(level[x]<level[y]) swap(x,y);
            ans+=(LL)(w-val[x])*sum[x]*(n-sum[x]);
            val[x]=w;
        }
    }
    return 0;
}
View Code