题目大意:有一颗树和m条链,每条链有个价值,你要选出若干两两点不相交的链使得选出来的链的价值之和最大。
n
,
m
≤
1
0
5
n,m\le10^5
n,m≤105
题解:显然dp,然后发现要维护的东西可以用一个线段树合并维护。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
namespace INPUT_SPACE{
const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;inline int gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
inline int inn() { int x,ch;while((ch=gc())<'0'||ch>'9');x=ch^'0';while((ch=gc())>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
}using INPUT_SPACE::inn;
const int N=100010,LOG=20;
struct edges{
int to,pre;
}e[N<<1];int h[N],etop,dp[N],rt[N],d[N],son[N],sz[N],top[N],fa[N];vector<pair<pii,int> > qry[N];
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
int fir_dfs(int x)
{
for(int i=h[x],y;i;i=e[i].pre) if((y=e[i].to)^fa[x])
fa[y]=x,sz[x]+=fir_dfs(y),(sz[y]>sz[son[x]]?son[x]=y:0);
return ++sz[x];
}
inline int sec_dfs(int x)
{
d[x]=d[fa[x]]+1;if(son[x]) son[x][top]=x[top],sec_dfs(son[x]);
for(int i=h[x],y;i;i=e[i].pre) if((y=e[i].to)!=fa[x]&&e[i].to!=son[x]) top[y]=y,sec_dfs(y);
return 0;
}
inline int getLCA(int x,int y) { for(;top[x]^top[y];x=top[x][fa]) if(top[x][d]<top[y][d]) swap(x,y);return d[x]<d[y]?x:y; }
namespace SEGMENT_MERGE_space{
const int T=N*LOG;int n,val[T],ch[T][2],node_cnt;
inline int build(int p,int v,int l,int r)
{
int x=++node_cnt;int mid=(l+r)>>1;if(l==r) return val[x]=v,x;
if(p<=mid) ch[x][0]=build(p,v,l,mid);else ch[x][1]=build(p,v,mid+1,r);return x;
}
inline int build(int p,int v) { return build(p,v,1,n); }
inline int update(int x,int v) { return val[x]+=v; }
inline int push_down(int x) { if(ch[x][0]) val[ch[x][0]]+=val[x];if(ch[x][1]) val[ch[x][1]]+=val[x];return val[x]=0; }
inline int query(int x,int p,int l,int r)
{
if(l==r) return val[x];int mid=(l+r)>>1;if(val[x]) push_down(x);
if(p<=mid) return query(ch[x][0],p,l,mid);return query(ch[x][1],p,mid+1,r);
}
inline int query(int x,int p) { return query(x,p,1,n); }
inline int _merge(int x,int y)
{
if(!x||!y) return x+y;if(val[x]) push_down(x);if(val[y]) push_down(y);
return ch[x][0]=_merge(ch[x][0],ch[y][0]),ch[x][1]=_merge(ch[x][1],ch[y][1]),x;
}
}using SEGMENT_MERGE_space::build;
using SEGMENT_MERGE_space::update;
using SEGMENT_MERGE_space::query;
using SEGMENT_MERGE_space::_merge;
inline int getdp(int x,int fa=0)
{
int tot=0;
for(int i=h[x],y;i;i=e[i].pre) if((y=e[i].to)^fa) getdp(y,x),tot+=dp[y];
rt[x]=build(x,dp[x]=tot);
for(int i=h[x],y;i;i=e[i].pre) if((y=e[i].to)^fa)
update(rt[y],tot-dp[y]),rt[x]=_merge(rt[x],rt[y]);
Rep(i,qry[x])
{
int u=qry[x][i].fir.fir,v=qry[x][i].fir.sec;
dp[x]=max(dp[x],query(rt[x],u)+query(rt[x],v)-tot+qry[x][i].sec);
}
return 0;
}
int main()
{
int n=inn(),x,y;rep(i,1,n-1) x=inn(),y=inn(),add_edge(x,y),add_edge(y,x);
fir_dfs(1),top[1]=1,sec_dfs(1);
for(int m=inn();m;m--) x=inn(),y=inn(),qry[getLCA(x,y)].pb(mp(mp(x,y),inn()));
return SEGMENT_MERGE_space::n=n,getdp(1),!printf("%d\n",dp[1]);
}