您的位置:首页 > 其它

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的更新就比较简单了,就不详说了

[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: