POJ - 3728 The merchant(dp+LCA)
2015-08-18 00:20
471 查看
题目大意:给出N个点,和每个点物品的售价,现在有一个商人,要从u点到v点,他想在路上多赚点钱。他可以从一个城市买物品,然后再卖到另一个城市,但买卖只允许一次,且不能回头走
问最多能赚多少
解题思路:果然智商捉急了。。
up数组纪录当前点到lca的最大利润
down数组纪录lca到当前点的最大利润
Max数组lca到当前点的最大值
Min纪录当前点到lca的最小值
这样的话,执行tarjan的时候,就可以更新一下这些值了
首先,答案的话肯定是max(max(up, down), Max - Min)
接着,怎么更新另外四个数组
(一下假设当前结点为u,祖先结点为v)
要更新up,应该要先更新距离lca近的祖先点,因为这样才不会重复
up[u] = max(up[u], max(up[v], Max[v] - Min[u]))
而更新down的话,也一样,也要先更新离lca近的祖先点
down[u] = max(down[u], max(down[v], Max[u] - Min[v]))
Min和Max的更新就比较简单了,就不详说了
问最多能赚多少
解题思路:果然智商捉急了。。
up数组纪录当前点到lca的最大利润
down数组纪录lca到当前点的最大利润
Max数组lca到当前点的最大值
Min纪录当前点到lca的最小值
这样的话,执行tarjan的时候,就可以更新一下这些值了
首先,答案的话肯定是max(max(up, down), Max - Min)
接着,怎么更新另外四个数组
(一下假设当前结点为u,祖先结点为v)
要更新up,应该要先更新距离lca近的祖先点,因为这样才不会重复
up[u] = max(up[u], max(up[v], Max[v] - Min[u]))
而更新down的话,也一样,也要先更新离lca近的祖先点
down[u] = max(down[u], max(down[v], Max[u] - Min[v]))
Min和Max的更新就比较简单了,就不详说了
[code]#include <cstdio> #include <algorithm> #include <cstring> using namespace std; #define N 50010 #define M 100010 struct Path{ int from, to, next; }P[M]; struct Query{ int from, to, next; }Q[M]; struct LCA{ int num, next; }L[M]; int head_Path , head_Query , head_LCA , f ; int up , down , Min , Max , ans ; int tot, n, q; bool vis ; void AddPdge_Path(int u, int v) { P[tot].from = u; P[tot].to = v; P[tot].next = head_Path[u]; head_Path[u] = tot++; u = u ^ v; v = u ^ v; u = u ^ v; P[tot].from = u; P[tot].to = v; P[tot].next = head_Path[u]; head_Path[u] = tot++; } void AddPdge_Query(int u, int v) { Q[tot].from = u; Q[tot].to = v; Q[tot].next = head_Query[u]; head_Query[u] = tot++; u = u ^ v; v = u ^ v; u = u ^ v; Q[tot].from = u; Q[tot].to = v; Q[tot].next = head_Query[u]; head_Query[u] = tot++; } void init() { for (int i = 1; i <= n; i++) { scanf("%d", &Min[i]); Max[i] = Min[i]; up[i] = down[i] = 0; } int u, v; memset(head_Path, -1, sizeof(head_Path)); tot = 0; for (int i = 1; i < n; i++) { scanf("%d%d", &u, &v); AddPdge_Path(u, v); } scanf("%d", &q); memset(head_Query, -1, sizeof(head_Query)); tot = 0; for (int i = 1; i <= q; i++) { scanf("%d%d", &u, &v); AddPdge_Query(u, v); } } int update(int u) { if (u == f[u]) return u; int t = f[u]; f[u] = update(f[u]); up[u] = max(up[u], max(up[t], Max[t] - Min[u])); down[u] = max(down[u], max(down[t], Max[u] - Min[t])); Min[u] = min(Min[u], Min[t]); Max[u] = max(Max[u], Max[t]); return f[u]; } void AddEdge_LCA(int lca, int num) { L[tot].num = num; L[tot].next = head_LCA[lca]; head_LCA[lca] = tot++; } void tarjan(int u) { vis[u] = true; f[u] = u; for (int i = head_Path[u]; ~i; i = P[i].next) { int v = P[i].to; if (!vis[v]) { tarjan(v); f[v] = u; } } for (int i = head_Query[u]; ~i; i = Q[i].next) { int v = Q[i].to; if (vis[v]) { int lca = update(v); AddEdge_LCA(lca, i); } } for (int i = head_LCA[u]; ~i; i = L[i].next) { int t = L[i].num; int u = Q[t].from; int v = Q[t].to; if (t & 1) { t ^= 1; u = u ^ v; v = u ^ v; u = u ^ v; } t /= 2; update(u); update(v); ans[t] = max(up[u], down[v]); ans[t] = max(ans[t], Max[v] - Min[u]); } } void solve() { memset(vis, 0, sizeof(vis)); memset(ans, 0, sizeof(ans)); memset(head_LCA, -1, sizeof(head_LCA)); tot = 0; tarjan(1); for (int i = 0; i < q; i++) printf("%d\n", ans[i]); } int main() { while (scanf("%d", &n) != EOF) { init(); solve(); } return 0; }
相关文章推荐
- 【Powershell】【Add-member】创建powershell对象
- .net基础概念
- 纯UILabel实现文字的竖排显示 记录
- Socket编程(TCP/UDP) - 初学(C语言)
- 如何解决 openvz 使用 sysctl 报错
- Oracle Coherence中文教程九:动态管理群集成员
- [toj4111] Binomial efficient
- Oracle Coherence中文教程八:启动和停止群集成员
- MVC不仅仅是设计模式
- jQuery中的append()和prepend(),after()和before()的区别
- Class.getResource与Class.getClassLoader.getResource归纳整理
- wpf 对一个集合操作的时候,怎么保留单张的信息
- Oracle Coherence中文教程六:Coherence集群简介
- java语言实现jsp页面验证码
- linux下互斥锁的使用
- java8 新特性
- Android开发中那些相见恨晚的方法、类、接口、工具
- nginx+tomcat+memcached实现session共享
- android tabhost Intent实现
- SqlServer 根据字段分类汇总信息