Main idea:
Given a tree with m chains distributed on this tree, each chain has a weight, and ask what the maximum weight is when the selected chains are not intersected
Question idea:
in ..
Stuck all night, got stuck in lca, vomit
First, find the lca of the m chains, and put the two end points of each chain into the lca.
Then you can perform tree dp
Let dp[i] denote the maximum weight of the non-duplicated chain selected by the subtree rooted at i
Then, for a root node u, there are two choices for the chain that passes u and the chain that does not pass u:
If you do not choose the chain that goes through u: then there is no restriction on the subtree, so sum += dp[e] //e is a child of u
If you choose a chain that goes through u:
Suppose there is a chain from 1->3, then the answer to this chain is the maximum value of the blue subtree.
It can be concluded that if there is a node u on this chain, then all the child node contributions of u should be added to the answer, but if v->u, and both u and v are on the chain, then u must be added All children of v + all children of v-node of u
So in summary, maintain one for each node: the dp value of all child nodes and-the dp value of the current node. Then the answer to selecting a chain after u is, the sum of all the child nodes of u + the sum of weights on the chain (x, y) + the weight of the chain
So use the tree to maintain it.
A few examples of comparison card holders are included~
Code:
/*** keep hungry and calm CoolGuang! ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18;
const ll maxn = 4e5+700;
const int mod= 998244353;
const int up = 1e9;
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
vector<int>v[maxn];
struct node{
int x,y,w;
};
vector<node>q[maxn];
int f[maxn][22],deep[maxn];
int son[maxn],sz[maxn],dfn = 0;
void dfs(int u,int fa){
deep[u] = deep[fa] + 1;
f[u][0] = fa;
for(int i=1;i<=20;i++) f[u][i] = f[f[u][i-1]][i-1];
sz[u] = 1;
for(int e:v[u]){
if(e == fa) continue;
dfs(e,u);
sz[u] += sz[e];
if(sz[son[u]] < sz[e]) son[u] = e;
}
}
int __LCA(int u,int v){
if(deep[u]<deep[v]) swap(u,v);
for(int i=20;i>=0;i--) if(deep[f[u][i]]>=deep[v]) u=f[u][i];
if(u==v) return u;
for(int i=20;i>=0;i--){
if(f[u][i]!=f[v][i]){
u=f[u][i];
v=f[v][i];
}
}
return f[u][0];
}
///LCA
///树剖
ll sum[maxn];
int top[maxn],L[maxn];
void add(int pos,ll w){
while(pos <= n){
sum[pos] += w;
pos += pos&-pos;
}
}
ll GetSum(int pos){
ll ans = 0;
while(pos){
ans += sum[pos];
pos -= pos&-pos;
}return ans;
}
void dfs1(int u,int fa,int t){
L[u] = ++dfn;
top[u] = t;
if(!son[u]) return ;///leaf
dfs1(son[u],u,t);
for(int e:v[u]){
if(e == fa || e == son[u]) continue;
dfs1(e,u,e);
}
}
///树形dp
ll dp[maxn];
ll QueryTree(int x,int y){///链x - > y
ll ans = 0;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]]) swap(x,y);
ans = ans+GetSum(L[x])-GetSum(L[top[x]]-1);
x=f[top[x]][0];
}
if(deep[x]>deep[y]) swap(x,y);
ans = ans + GetSum(L[y])-GetSum(L[x]-1);
return ans;
}
ll ans = 0;
void Tree_dp(int u,int fa){
ll temp = 0;
for(int e:v[u]){
if(e == fa) continue;
Tree_dp(e,u);
temp += dp[e];
}
dp[u] = temp;
for(node tt:q[u]){
int x = tt.x,y = tt.y,w = tt.w;
dp[u] = max(dp[u],temp+QueryTree(x,u)+QueryTree(y,u)+w);
}
add(L[u],temp-dp[u]);
}
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);read(m);
dfn = 0;
for(int i=1;i<=n;i++) v[i].clear(),q[i].clear(),son[i] = 0;
for(int i=0;i<=n;i++) dp[i] = 0,sum[i] = 0;
for(int i=1;i<=n-1;i++){
int x,y;read(x);read(y);
v[x].push_back(y);
v[y].push_back(x);
}
deep[1] = 0;
dfs(1,1);
dfs1(1,1,1);
for(int i=1;i<=m;i++){
int x,y,w;read(x);read(y);read(w);
int lca = __LCA(x,y);
q[lca].push_back(node{x,y,w});
}
/* for(int i=1;i<=n;i++){
for(node tt:q[i]){
printf("%d:%d %d %d\n",i,tt.x,tt.y,tt.w);
}
}*/
ans = 0;
Tree_dp(1,1);
/* for(int i=1;i<=n;i++)
printf("%lld ",dp[i]);
printf("\n");*/
printf("%lld\n",dp[1]);
}
return 0;
}
/***
4
7 4
1 2
1 3
2 4
2 5
3 6
3 7
1 4 7
2 4 5
1 6 5
6 6 5
7 3
1 2
1 3
2 4
2 5
3 6
3 7
1 4 1
5 5 1
6 7 1
4 3
1 2
2 3
2 4
2 2 5
3 4 6
1 1 2
7 4
1 2
1 3
2 4
2 5
3 6
3 7
1 5 4
4 4 2
4 3 7
5 5 2
***/