码迷,mamicode.com
首页 > 其他好文 > 详细

POJ - 3728 The merchant(dp+LCA)

时间:2015-08-18 01:18:16      阅读:122      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:给出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的更新就比较简单了,就不详说了

#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[N], head_Query[N], head_LCA[N], f[N];
int up[N], down[N], Min[N], Max[N], ans[N];
int tot, n, q;
bool vis[N];

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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

POJ - 3728 The merchant(dp+LCA)

标签:

原文地址:http://blog.csdn.net/l123012013048/article/details/47736973

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!