题意:
在树上给出一些链,链上有权值
求一个最大的链集合的权值和,集合内的链不相交
思路:
把每条链的状态放到lca(u,v)上,然后进行树形dp
dp[u]有两种状态
1.不取链
dp[u]=∑dp[Son[u]]
2.取一个lca(x,y)==u的链加上
因为要取这条链,所以我们应该减掉子树上取了相交的链多加的值
因为点有点多,而且对于链操作
很容易想到dfs序或者树剖(树剖太长了… 所以dfs序就好啦…
对于每个点,我们维护一下dp[u]-Sum[u]
Sum[u]=不取链的u的dp值=∑dp[Son[u]]
然后把整条链的dp[u]-Sum[u]全都减掉就好啦
dfs序有个特殊的技巧
就是把Out也多加一个点,但是在线段树上是*-1
这样我们在遍历父亲节点到右子树的上的点的链就直接In[u]~In[x]就好啦
因为左子树上的In会被Out减掉
好久没写blog了,因为要准备区域赛(懒得写….
希望能拿到不辜负自己的成绩吧…
但是不管结果怎样,总不会后悔参加这么好玩的比赛>_<
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<bitset>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x&(-x))
typedef long long LL;
const int maxn = 200005;
const int inf=(1<<31)-1;
vector<int>vec[maxn];
vector<pair<int,pair<int,int> > >chain[maxn];
int In[maxn*2],Out[maxn*2],Zf[maxn*2],deep[maxn],tot;
int ft[maxn][20],Pow[20];
void dfs(int u,int fa,int dep)
{
In[u]=++tot;
Zf[tot]=1;
deep[u]=dep;
for(int i=1;i<20;++i)
{
if(dep<Pow[i])
break;
ft[u][i]=ft[ft[u][i-1]][i-1];
}
int Size=vec[u].size();
for(int i=0;i<Size;++i)
{
int v=vec[u][i];
if(v!=fa)
{
ft[v][0]=u;
dfs(v,u,dep+1);
}
}
Out[u]=++tot;
Zf[tot]=-1;
}
int lca(int u,int v)
{
if(deep[u]<deep[v])
swap(u,v);
int t=deep[u]-deep[v];
for(int i=0;i<20;++i)
if(t&Pow[i])
u=ft[u][i];
for(int i=19;i>=0;--i)
if(ft[u][i]!=ft[v][i])
{
u=ft[u][i];
v=ft[v][i];
}
if(u==v)
return u;
return ft[u][0];
}
int tree[maxn*4],lazy[maxn*4],Sub[maxn*4];
void Push_up(int rt)
{
tree[rt]=tree[rt*2]+tree[rt*2+1];
}
void Push_down(int rt)
{
if(lazy[rt])
{
lazy[rt*2]+=lazy[rt];
lazy[rt*2+1]+=lazy[rt];
tree[rt*2]+=lazy[rt]*Sub[rt*2];
tree[rt*2+1]+=lazy[rt]*Sub[rt*2+1];
lazy[rt]=0;
}
}
void build(int l,int r,int rt)
{
tree[rt]=lazy[rt]=0;
if(l==r)
{
Sub[rt]=Zf[l];
return ;
}
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
Sub[rt]=Sub[rt*2]+Sub[rt*2+1];
}
void Insert(int l,int r,int left,int right,int x,int rt)
{
if(left<=l&&r<=right)
{
tree[rt]+=x*Sub[rt];
lazy[rt]+=x;
return ;
}
Push_down(rt);
int mid=(l+r)/2;
if(left<=mid)
Insert(l,mid,left,right,x,rt*2);
if(right>mid)
Insert(mid+1,r,left,right,x,rt*2+1);
Push_up(rt);
}
int Query(int l,int r,int left,int right,int rt)
{
if(left<=l&&r<=right)
return tree[rt];
Push_down(rt);
int tmp=0;
int mid=(l+r)/2;
if(left<=mid)
tmp+=Query(l,mid,left,right,rt*2);
if(right>mid)
tmp+=Query(mid+1,r,left,right,rt*2+1);
return tmp;
}
int dp[maxn],Sum[maxn];
void Dfs(int u,int fa)
{
dp[u]=Sum[u]=0;
int Size=vec[u].size();
for(int i=0;i<Size;++i)
{
int v=vec[u][i];
if(v!=fa)
{
Dfs(v,u);
Sum[u]+=dp[v];
}
}
dp[u]=Sum[u];
Size=chain[u].size();
for(int i=0;i<Size;++i)
{
int x=chain[u][i].first;
int y=chain[u][i].second.first;
int w=chain[u][i].second.second;
int Ans=Sum[u]+w;
Ans-=Query(1,tot,In[u],In[x],1);
Ans-=Query(1,tot,In[u],In[y],1);
//printf("*%d *%d\n",Query(1,tot,In[u],In[x],1),Query(1,tot,In[u],In[y],1));
dp[u]=max(dp[u],Ans);
}
//printf("%d(dp: %d Sum: %d )\n",u,dp[u],Sum[u]);
Insert(1,tot,In[u],In[u],dp[u]-Sum[u],1);
Insert(1,tot,Out[u],Out[u],dp[u]-Sum[u],1);
}
int main()
{
Pow[0]=1;
for(int i=1;i<20;++i)
Pow[i]=Pow[i-1]*2;
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
vec[i].clear();
chain[i].clear();
}
for(int i=1;i<n;++i)
{
int u,v;
scanf("%d%d",&u,&v);
vec[u].push_back(v);
vec[v].push_back(u);
}
tot=0;
memset(ft,0,sizeof(ft));
dfs(1,-1,0);
//for(int i=1;i<=n;++i) printf("%d(%d,%d) ",i,In[i],Out[i]);printf("\n");
//for(int i=1;i<=tot;++i) printf("%d ",Zf[i]);printf("\n");
memset(dp,0,sizeof(dp));
for(int i=1;i<=m;++i)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
chain[lca(u,v)].push_back(make_pair(u,make_pair(v,w)));
}
build(1,tot,1);
Dfs(1,-1);
printf("%d\n",dp[1]);
}
return 0;
}