标签:
题目: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<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<cmath> #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<int> g[N]; vector<int> 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<g[x].size();i++)if(g[x][i]!=pre){ int u = g[x][i]; dep[u] = dep[x] + 1; dfs(u,x); } ed[x] = clock; } void lca_init(){ clock = 0; dep[1] = 1; dfs(1,-1); for(int i=1;i<=maxh-1;i++){ for(int j=1;j<=n;j++) if(anc[j][i-1]<0) anc[j][i] = -1; else anc[j][i] = anc[anc[j][i-1]][i-1]; } } int swim(int x,int H){ for(int i=0;H;i++){ if(H&1) x = anc[x][i]; H >>= 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<g[x].size();i++)if(g[x][i]!=pre){ int u = g[x][i]; sum[x] += dfs_tree(u,x); } d[x] = sum[x]; for(int i=0;i<list[x].size();i++){ int id = list[x][i]; ll tmp = p[id].w ; ll tmp1 = find(p[id].u,p[id].v,x); tmp += tmp1; d[x] = max(d[x] , tmp); } // update insert(1,1,n,st[x],ed[x],d[x],sum[x]); return d[x]; } void solve(){ memset(d,-1,sizeof(d)); memset(tree,0,sizeof(tree)); lca_init(); for(int i=1;i<=n;i++) list[i].clear(); for(int i=1;i<=m;i++){ int u = p[i].u , v = p[i].v; int la = lca(u,v); list[la].push_back(i); } dfs_tree(1,-1); } int main(){ int T; cin >> 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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdu5293 Tree chain problem 树形dp+线段树
标签:
原文地址:http://blog.csdn.net/alpc_wt/article/details/46999729