题目链接

题意:

  有n个点的一棵树。其中树上有m条已知的链,每条链有一个权值。从中选出任意个不相交的链使得链的权值和最大。

思路:

  树形DP。设dp[i]表示i的子树下的最优权值和,sum[i]表示不考虑i点时子树的最优权值和,即(j是i的儿子),显然dp[i]>=sum[i]。那么问题是考虑i点时dp[i]的值是多少,假设有一条链通过i,且端点a和b都在i的子树里,即LCA(a,b)=i,如果考虑加上这条链的权值,那么a->i, b->i的路上的点v都不能有链经过它们(题目要求链不相交),那么-dp[v],但至少有sum[v],即,其中v是某条链上的点。那么怎么快速求出sigma的值呢,想到树状数组维护前缀和。那么怎么遍历呢,用DFS序遍历,思想和“粮食分配”一样,在L[v]上修改,在R[v]上恢复。

#include <bits/stdc++.h>
using namespace std; const int N = 1e5 + 5;
const int D = 20; struct Chain {
int u, v, w;
};
vector<Chain> chains[N];
vector<int> edges[N];
int dp[N], sum[N];
int n, m;
int tim; void init() {
for (int i=1; i<=n; ++i) {
edges[i].clear ();
chains[i].clear ();
}
} int rt[N][D], dep[N]; void init_LCA() {
for (int j=1; j<D; ++j) {
for (int i=1; i<=n; ++i) {
rt[i][j] = rt[i][j-1] ? rt[rt[i][j-1]][j-1] : 0;
}
}
} int LCA(int u, int v) {
if (dep[u] < dep[v]) swap (u, v);
for (int i=0; i<D; ++i) {
if ((dep[u] - dep[v]) >> i & 1) {
u = rt[u][i];
}
}
if (u == v) return u;
for (int i=D-1; i>=0; --i) {
if (rt[u][i] != rt[v][i]) {
u = rt[u][i];
v = rt[v][i];
}
}
return rt[u][0];
} struct BIT {
int C[N];
int n;
void init(int n) {
this->n = n;
memset (C, 0, sizeof (C));
}
void updata(int i, int x) {
for (; i<=n; i+=i&-i) C[i] += x;
}
int query(int i) {
int ret = 0;
for (; i>0; i-=i&-i) ret += C[i];
return ret;
}
}bsum, bdp; int L[N], R[N]; void DFS(int u, int pa) {
L[u] = tim++;
dep[u] = dep[pa] + 1;
rt[u][0] = pa;
for (auto v: edges[u]) {
if (v == pa) continue;
DFS (v, u);
}
R[u] = tim;
} void DFS(int u) {
sum[u] = 0;
for (auto v: edges[u]) {
if (v == rt[u][0]) continue;
DFS (v);
sum[u] += dp[v];
}
dp[u] = sum[u];
for (auto chain: chains[u]) {
int a = chain.u, b = chain.v, c = chain.w;
int tmp = bsum.query (L[a]) - bdp.query (L[a]) + bsum.query (L[b]) - bdp.query (L[b]);
dp[u] = max (dp[u], sum[u] + tmp + c);
}
bsum.updata (L[u], sum[u]);
bsum.updata (R[u], -sum[u]);
bdp.updata (L[u], dp[u]);
bdp.updata (R[u], -dp[u]);
} void prepare() {
dep[0] = 0;
tim = 1;
DFS (1, 0);
init_LCA ();
bsum.init (n);
bdp.init (n);
} int main() {
int T;
scanf ("%d", &T);
while (T--) {
init ();
scanf ("%d%d", &n, &m);
for (int i=1; i<n; ++i) {
int u, v;
scanf ("%d%d", &u, &v);
edges[u].push_back (v);
edges[v].push_back (u);
} prepare (); for (int i=1; i<=m; ++i) {
int u, v, w;
scanf ("%d%d%d", &u, &v, &w);
int lca = LCA (u, v);
chains[lca].push_back ((Chain) {u, v, w});
} DFS (1);
printf ("%d\n", dp[1]);
}
return 0;
}

  

树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)的更多相关文章

  1. HDU 5293 Annoying problem 树形dp dfs序 树状数组 lca

    Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 Description Coco has a tree, w ...

  2. 洛谷P3374 【模板】树状数组 1&&P3368 【模板】树状数组 2题解

    图片来自度娘~~ 树状数组形如上图,是一种快速查找区间和,快速修改的一种数据结构,一个查询和修改复杂度都为log(n),树状数组1和树状数组2都是板子题,在这里进行详解: 求和: 首先我们看一看这个图 ...

  3. [HDU 5293]Tree chain problem(树形dp+树链剖分)

    [HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...

  4. HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...

  5. HDU 5293 Train chain Problem - 树链剖分(树状数组) + 线段树+ 树型dp

    传送门 题目大意: 一颗n个点的树,给出m条链,第i条链的权值是\(w_i\),可以选择若干条不相交的链,求最大权值和. 题目分析: 树型dp: dp[u][0]表示不经过u节点,其子树的最优值,dp ...

  6. 线段树(单点更新)/树状数组 HDOJ 1166 敌兵布阵

    题目传送门 /* 线段树基本功能:区间值的和,修改某个值 */ #include <cstdio> #include <cstring> #define lson l, m, ...

  7. 树状数组 Binary Indexed Tree/Fenwick Tree

    2018-03-25 17:29:29 树状数组是一个比较小众的数据结构,主要应用领域是快速的对mutable array进行区间求和. 对于一般的一维情况下的区间和问题,一般有以下两种解法: 1)D ...

  8. [bzoj1901][zoj2112][Dynamic Rankings] (整体二分+树状数组 or 动态开点线段树 or 主席树)

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

  9. HDU 3436--Queue-jumpers (树状数组 or Splay Tree)

    树状数组这个真心想了好久,还是没想出来 %%% www.cppblog.com/Yuan/archive/2010/08/18/123871.html 树状数组求前缀和大于等于k的最大值,第一次看到这 ...

随机推荐

  1. controller_name classify constantize model_name

    控制器 class CourseSurveysController < ResourcesBaseController end controller_name # "course_su ...

  2. java从基础知识(十)java多线程(上)

    线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元.另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点 ...

  3. ASP.NET运作流程

    当我们在浏览器输入域名访问服务器资源时,会向服务器发送Http请求,并经由IIS处理后,交由ASP.NET托管程序处理,进入ASP.NET管道.在IIS内部如何处理我们不需要深入去了解,在ASP.NE ...

  4. 高程(4):执行环境、作用域、上下文执行过程、垃圾收集、try...catch...

    高程三 4.2.4.3 一.执行环境 1.全局执行环境是最外层的执行环境. 2.每个函数都有自己的执行环境,执行函数时,函数环境就会被推入一个当前环境栈中,执行完毕,栈将其环境弹出,把控制器返回给之前 ...

  5. JSON中eval与parse的区别

    json的的解析方法 (非原创) json的解析方法共有两种:eval_r() 和 JSON.parse(),使用方法如下: var jsonData = '{"data1":&q ...

  6. 使用Visual Leak Detector for Visual C++ 捕捉内存泄露

    什么是内存泄漏? 内存泄漏(memory leak),指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况.内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段 ...

  7. spring定时任务详解(@Scheduled注解)( 转 李秀才的博客 )

    在springMVC里使用spring的定时任务非常的简单,如下: (一)在xml里加入task的命名空间 xmlns:task="http://www.springframework.or ...

  8. html中嵌入swf文件的几种方法

    转自:http://blog.163.com/yuki_1154/blog/static/7120277120126109315935/ 找了很久终于找到一个比较全面的: 1. object + em ...

  9. APM程序分析-AC_WPNav.cpp

    APM程序分析 主程序在ArduCopter.cpp的loop()函数. /// advance_wp_target_along_track - move target location along ...

  10. mysqlDBA(1-3年)

    1.熟悉Aliyun操作系统的管理.配置和系统调优: 2.熟悉mysql管理 3.熟悉mysql主从复制,主主复制 4.熟悉数据库的备份策略,监控策略,性能测量策略 5.熟悉linux/unix操作系 ...