标签:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5293
题意:给你一棵n个点的树,和一些该树上的树链,每个树链有一定的权值,要求选出一些不相交的树链,使他们的权值和尽量大
解:
树形dp,dp[x]表示以x为根节点的子树的解,那么就可以基于在当前结点对树链的选和不选进行dp
现在有两个问题:
1、在树链上的哪个点进行选择?
2、选和不选分别如何操作?
对于第一个问题,粗略想一下(在解决问题二的时候会发现),树链上最浅的一个点(也就是树链两端的lca)上选择是可行的
对于第二个问题,(假设现在在点u)不选的话,dp[u]=Sum(dp[v])(v为u的子节点),用sum[u]记录Sum(dp[v])(v为u的子节点),有dp[u]=sum[u]
选择的话,对于每一个lca在u点的树链c,
dp[u]=max(dp[u],Sum(dp[v1])+c.w(v1为c上所有节点的子节点, c.w为该链的权值))
dp[u]=max(dp[u],Sum(sum[x])-Sum(dp[x])+c.w(x为c上所有节点, c.w为该链的权值))
这个链上所有节点的某值和,用dfs序+树状数组维护一下就好了
1 /* 2 * Problem: 3 * Author: SHJWUDP 4 * Created Time: 2015/8/2 星期日 22:07:32 5 * File Name: 233.cpp 6 * State: 7 * Memo: 8 */ 9 #include <iostream> 10 #include <cstdio> 11 #include <cstring> 12 #include <algorithm> 13 #include <vector> 14 #pragma comment(linker, "/STACK:1024000000,1024000000") 15 16 using namespace std; 17 18 struct Edge { 19 int u, v; 20 Edge(int u, int v):u(u), v(v){} 21 }; 22 struct Chain { 23 int a, b, w; 24 int lca; 25 }; 26 struct Fenwick { 27 int n; 28 vector<int> c; 29 void init(int n) { 30 this->n=n; 31 c.assign(n+1, 0); 32 } 33 int lowbit(int x) { 34 return x & -x; 35 } 36 void add(int x, int v) { 37 while(x<=n) { 38 c[x]+=v; x+=lowbit(x); 39 } 40 } 41 int getsum(int x) { 42 int res=0; 43 while(x>0) { 44 res+=c[x]; x-=lowbit(x); 45 } 46 return res; 47 } 48 } fw1, fw2; 49 50 int n, m; 51 vector<Edge> edges; 52 vector<vector<int> > G; 53 vector<Chain> chain; 54 vector<int> ln, rn, dep, dp, sum; 55 vector<vector<int> > fa, arr; 56 int root, cnt; 57 void init(int sz) { 58 edges.clear(); 59 G.assign(sz, vector<int>(0)); 60 chain.resize(sz); 61 ln.resize(sz); rn.resize(sz); dep.resize(sz); dp.resize(sz); sum.resize(sz); 62 fa.assign(sz, vector<int>(20)); 63 arr.assign(sz, vector<int>(0)); 64 fw1.init(sz<<1); fw2.init(sz<<1); 65 } 66 void addEdge(int u, int v) { 67 edges.push_back(Edge(u, v)); 68 G[u].push_back(edges.size()-1); 69 } 70 void dfs1(int u) { 71 ln[u]=++cnt; 72 for(int k=1; k<20; k++) fa[u][k]=fa[fa[u][k-1]][k-1]; 73 for(int i : G[u]) { 74 Edge & e=edges[i]; 75 if(e.v==fa[u][0]) continue; 76 fa[e.v][0]=u; 77 dep[e.v]=dep[u]+1; 78 dfs1(e.v); 79 } 80 rn[u]=++cnt; 81 } 82 int lca(int u, int v) { 83 if(dep[u]<dep[v]) swap(u, v); 84 for(int k=19; k>=0; k--) { 85 if(dep[fa[u][k]]>=dep[v]) { 86 u=fa[u][k]; 87 } 88 } 89 if(u==v) return u; 90 for(int k=19; k>=0; k--) { 91 if(fa[u][k]!=fa[v][k]) { 92 u=fa[u][k]; v=fa[v][k]; 93 } 94 } 95 return fa[u][0]; 96 } 97 void dfs2(int u) { 98 dp[u]=sum[u]=0; 99 for(int i : G[u]) { 100 Edge & e=edges[i]; 101 if(e.v==fa[u][0]) continue; 102 dfs2(e.v); 103 sum[u]+=dp[e.v]; 104 } 105 dp[u]=sum[u]; 106 for(int i : arr[u]) { 107 Chain & c=chain[i]; 108 int tmp=fw1.getsum(ln[c.a])+fw1.getsum(ln[c.b]) 109 -fw2.getsum(ln[c.a])-fw2.getsum(ln[c.b])+sum[u]; 110 dp[u]=max(dp[u], tmp+c.w); 111 } 112 fw1.add(ln[u], sum[u]); fw1.add(rn[u], -sum[u]); 113 fw2.add(ln[u], dp[u]); fw2.add(rn[u], -dp[u]); 114 } 115 int main() { 116 #ifndef ONLINE_JUDGE 117 freopen("in", "r", stdin); 118 //freopen("out", "w", stdout); 119 #endif 120 int T; 121 scanf("%d", &T); 122 while(T--) { 123 scanf("%d%d", &n, &m); 124 init(n+1); 125 for(int i=1; i<n; i++) { 126 int a, b; 127 scanf("%d%d", &a, &b); 128 addEdge(a, b); 129 addEdge(b, a); 130 } 131 root=1; cnt=0; dep[root]=0; fa[root][0]=root; dfs1(root); 132 for(int i=0; i<m; i++) { 133 scanf("%d%d%d", &chain[i].a, &chain[i].b, &chain[i].w); 134 chain[i].lca=lca(chain[i].a, chain[i].b); 135 arr[chain[i].lca].push_back(i); 136 } 137 dfs2(root); 138 printf("%d\n", dp[root]); 139 } 140 return 0; 141 }
[2015hdu多校联赛补题]hdu5293 Tree chain problem
标签:
原文地址:http://www.cnblogs.com/shjwudp/p/4697045.html