解法
設f[i]表示覆蓋了i的子樹和i的返祖邊的最小代價,那麼答案就是,但是f[i]的方案不一定是最終的最優方案,如果某個方案可以向上延伸的更長,即使現在代價比較高,也有可能是最終更優的方案,所以我們需要維護所有有可能成爲答案的方案。然後再給當前點選出一個最小的作爲f。
因爲要選最小值,所以考慮使用小根堆。
轉移的方法:對於,從x轉移到y,對於x的小根堆裏的一個方案:如果它不能延伸到y的父親,就需要把它刪了,否則這個方案(設其權值爲val)會對y提供一種權值爲,延伸位置不變的方案。
然後對於需要刪除的方案,不需要直接刪除,而是在其成爲堆頂以後再刪除。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+5;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,m;
struct edge{
int v,p;
}e[maxn<<1];
int h[maxn],cnt;
inline void add(int a,int b){
e[++cnt].p=h[a];
e[cnt].v=b;
h[a]=cnt;
e[++cnt].p=h[b];
e[cnt].v=a;
h[b]=cnt;
}
typedef pair<int,int> pii;
vector<pii> g[maxn];
int dep[maxn];
ll f[maxn],ans;
struct node{
pair<ll,int> x;
ll z;
int l,r,fa,d;
}t[maxn];
#define fi first
#define se second
inline void add(int x,ll k){
if(x)t[x].x.fi+=k,t[x].z+=k;
}
inline void pushdown(int x){
add(t[x].l,t[x].z);
add(t[x].r,t[x].z);
t[x].z=0;
}
inline int merge(int x,int y){
if(!x||!y)return x|y;
if(t[x].x>t[y].x)swap(x,y);
if(t[x].z)
pushdown(x);
t[x].r=merge(t[x].r,y);
t[t[x].r].fa=x;
if(t[t[x].r].d>t[t[x].l].d)swap(t[x].l,t[x].r);
t[x].d=t[t[x].r].d+1;
return x;
}
int tot,rt[maxn];
void dfs(int u,int fa){
dep[u]=dep[fa]+1;
for(auto o:g[u]){tot++;
t[tot].x=o,t[tot].d=1;rt[u]=merge(rt[u],tot);
}
ll s=0;
for(int i=h[u];i;i=e[i].p){
int v=e[i].v;
if(v==fa)continue;
dfs(v,u);s+=f[v];
add(rt[v],-f[v]);rt[u]=merge(rt[u],rt[v]);
}
add(rt[u],s);
while(rt[u]&&dep[t[rt[u]].x.se]>=dep[u]){
if(t[rt[u]].z)
pushdown(rt[u]);
rt[u]=merge(t[rt[u]].l,t[rt[u]].r);
}
if(!rt[u]){puts("-1");exit(0);}
f[u]=t[rt[u]].x.fi;
}
signed main(){
n=read(),m=read();
for(int i=1;i<n;i++){
int x=read(),y=read();
add(x,y);
}
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
g[x].push_back(pii(z,y));
}
dep[1]=1;
for(int i=h[1];i;i=e[i].p){
int v=e[i].v;
dfs(v,1);ans+=f[v];
}
printf("%lld\n",ans);
return 0;
}