题目:https://hihocoder.com/problemset/problem/1238?sid=1369284
一道很不错的题目。
思路:对于任意一条边(a,b),权值为w,以a为根的子树节点数目为node[a],以b为根的子树节点node[b],则该边被计算node[a]*node[b]*w次。利用DFS对所有节点进行遍历。
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
typedef long long llong;
typedef pair<int,llong> Pair;
const int N=1e6+4;
vector<vector<Pair>> g(N);
llong total=0LL;
int root=1;
vector<int> level(N,0);
vector<int> node(N,0);
vector<llong> path(N,0);
int n,m;
void dfs(int rt){
node[rt]=1;
for(auto e:g[rt]){
if(level[e.first]==0){
path[e.first]=e.second;
level[e.first]=level[rt]+1;
dfs(e.first);
node[rt]+=node[e.first];
total+=(llong)node[e.first]*(n-node[e.first])*e.second;
}
}
}
void edit(int u,int v,llong w){
if(level[u]<level[v]){
swap(u,v);
}
llong delta=w-path[u];
total+=delta*node[u]*(n-node[u]);
path[u]=w;
}
int main() {
scanf("%d%d",&n,&m);
int u,v;
llong k;
for(int i=0;i<n;++i){
scanf("%d%d%lld",&u,&v,&k);
g[u].push_back(Pair(v,k));
g[v].push_back(Pair(u,k));
}
char op[10];
level[root]=1;
dfs(1);
while(m--){
scanf("%s",op);
if(op[0]=='Q'){
printf("%lld\n",total);
}else{
scanf("%d%d%lld",&u,&v,&k);
edit(u,v,k);
}
}
return 0;
}