题目:http://acm.hdu.edu.cn/showproblem.php?pid=5293
在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大。
比赛的时候以为是树链剖分就果断没去想,其实是没思路。
看了题解,原来是树形dp,话说多校第一场树形dp还真多。。。。
维护d[i],表示以i为根节点的子树的最优答案。
sum[i]表示i的儿子节点(只能是儿子节点)的d值和。
那么答案就是d[root]。
如何更新d值
d[i] = max(sum[i] , w[p]+sigma sum[j] - sigma d[j] ); p为以i为lca的链 ,j为链上的点(注意:不需要减去d[i])
也就是,对于i,
要么是不选i,答案即sum[i],他的儿子和。
要么是选i,即找一条过i的链,链的权值 + 这棵子树上不在链上的距离链最近的点的d值和。
维护链上的的sum和,d和 用线段树。
先通过树的遍历序将树上的节点链话。然后区间修改,单点查询。(每个点的信息是改点到根节点路径上的和)
代码:
#include
#include
#include
#include
#include
#include
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int N = 100000+10;
typedef long long ll;
const int maxh = 25;
int st[N],ed[N],clock;
// ************************************
#define Lson Ls,L,mid
#define Rson Rs,mid+1,R
const int maxn = 100000+10;
const int inf = 100000000;
struct Node{
ll val, set;
ll val2 , set2;
}tree[N<<2];
inline void update(Node& fa, Node& Ls, Node& Rs){
fa.val = Ls.val + Rs.val;
fa.val2 = Ls.val2 + Rs.val2;
}
inline void pushdown(Node& fa, Node& Ls, Node& Rs){
if (fa.set != 0){
Ls.val += fa.set; Ls.set += fa.set;
Rs.val += fa.set; Rs.set += fa.set;
fa.set = 0;
}
if (fa.set2 != 0){
Ls.val2 += fa.set2; Ls.set2 += fa.set2;
Rs.val2 += fa.set2; Rs.set2 += fa.set2;
fa.set2 = 0;
}
}
void insert(int v, int L, int R, int p, int q, ll delta,ll delta2){
if(p<=st[2]&& q>=st[2]&& delta2) {
}
if (p<=L && R<=q){
tree[v].val += delta;
tree[v].set += delta;
tree[v].val2 += delta2;
tree[v].set2 += delta2;
return;
}
int Ls = v<<1, Rs = Ls+1, mid = (L+R)/2;
pushdown(tree[v], tree[Ls], tree[Rs]);
if (q<=mid) insert(Lson, p, q, delta,delta2);
else if (p>mid) insert(Rson, p, q, delta,delta2);
else{
insert(Lson, p, q, delta,delta2);
insert(Rson, p, q, delta,delta2);
}
// update(tree[v], tree[Ls], tree[Rs]);
}
ll query(int v, int L, int R,int ql, int qr){
if(ql<=L && R<=qr){
return tree[v].val;
}
int Ls = v<<1, Rs = Ls+1, mid = (L+R)/2;
pushdown(tree[v], tree[Ls], tree[Rs]);
ll ans = 0;
if(qr<=mid) ans = query(Lson,ql,qr);
else if(ql>mid) ans = query(Rson,ql,qr);
else{
ans = query(Lson,ql,qr) + query(Rson,ql,qr);
}
// update(tree[v], tree[Ls], tree[Rs]);
return ans ;
}
ll query2(int v, int L, int R,int ql, int qr){
if(ql<=L && R<=qr){
return tree[v].val2;
}
int Ls = v<<1, Rs = Ls+1, mid = (L+R)/2;
pushdown(tree[v], tree[Ls], tree[Rs]);
ll ans = 0;
if(qr<=mid) ans = query2(Lson,ql,qr);
else if(ql>mid) ans = query2(Rson,ql,qr);
else{
ans = query2(Lson,ql,qr) + query2(Rson,ql,qr);
}
// update(tree[v], tree[Ls], tree[Rs]);
return ans ;
}
// ***************************************
ll d[N],sum[N];
vector g[N];
vector list[N];
struct pp{
int u,v,w;
}p[N];
int n,m,dep[N];
int anc[N][maxh+1];
void dfs(int x,int pre){
st[x] = ++clock;
anc[x][0] = pre;
for(int i=0;i>= 1;
}
return x;
}
int lca(int u,int v){
if(dep[u]>dep[v]) swap(u,v);
int H = dep[v]-dep[u];
v = swim(v,H);
if(u==v) return u;
for(int k=maxh-1;k>=0;k--)
if(anc[u][k]!=anc[v][k]){
u = anc[u][k];
v = anc[v][k];
}
return anc[u][0];
}
ll find(int u,int v,int la){
ll ans = 0;
ll s1 = query2(1,1,n,st[u],st[u]);
ll s2 = query2(1,1,n,st[v],st[v]);
ans = s1 + s2;
ll d1 = query(1,1,n,st[u],st[u]);
ll d2 = query(1,1,n,st[v],st[v]);
ans -= d1 + d2;
return ans+sum[la];
}
ll dfs_tree(int x,int pre){
if(d[x]!=-1) return d[x];
ll res = 0;
sum[x] = 0;
for(int i=0;i> T;
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) g[i].clear();
for(int i=1;i<=n-1;i++){
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].w);
}
solve();
printf("%I64d\n",d[1]);
}
return 0;
}