您的位置:首页 > 其它

*POJ 3728 - The merchant(LCA‘ Tarjan)

2015-07-29 15:46 447 查看
题目:

http://poj.org/problem?id=3728

题意:

n个点,每个点都有相应的货物价格,n-1条边。

Q个询问,给出起点u终点v,在u到v 的路径上,最多做买卖一次,求出最大的获利数。(可以不做买卖)。

思路:

LCA的离线算法。

根据题目分析:假设(u,v)的最近公共祖先是lca,答案可能在路径(u,lca),用数组up【u】记录从u到lca的最大获利数;或是路径(lca,v),用数组down【v】记录从lca到v 的最大获利数;或是(lca,v)的最大值 减去 (u,lca)的最小值。

所以应该记录这四个数组的值,在find函数中进行更新。

在dfs中查看相关的询问,假设询问(u,v),v已被访问过,则v的lca 就是 u和v的lca,将该询问加入到 lca的集合中。

等到lca的所有子节点都访问过了之后再来处理lca中的询问,得出答案。

AC.

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int maxn = 5e4+5;
int val[maxn];
int Q, n;

bool vis[maxn];
int lca[maxn], up[maxn], down[maxn], ans[maxn];
int maxx[maxn], minn[maxn];

int tot, head[maxn];
struct Edge {
int to, next;
}edge[2*maxn];
void addedge(int u, int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}

int h[maxn], tt;
struct Que{
int u, v, id, next;
}que[2*maxn];
void addask(int u, int v, int id)
{
que[tt].u = u;
que[tt].v = v;
que[tt].id = id;
que[tt].next = h[u];
h[u] = tt++;
}

int hh[maxn], tol;
struct Ans{
int n, next;
}anss[2*maxn];
void addans(int u, int v)
{
anss[tol].n = v;
anss[tol].next = hh[u];
hh[u] = tol++;
}

int par[maxn];
int find(int x)
{
if(par[x] == x) return x;
int f = par[x];
par[x] = find(par[x]);

up[x] = max(up[x], max(up[f], maxx[f] - minn[x]));
down[x] = max(down[x], max(down[f], maxx[x] - minn[f]));
maxx[x] = max(maxx[x], maxx[f]);
minn[x] = min(minn[x], minn[f]);

return par[x];
}

void unite(int a, int b)
{
int x = find(a), y = find(b);
par[y] = x;
}

void LCA(int u)
{
for(int i = h[u]; ~i; i = que[i].next) {
int v = que[i].v;
if(vis[v]) {
int lca = find(v);
//printf("v= %d: %d\n", v, lca);
addans(lca, i);
}
} //遍历到根后才能记录答案。

vis[u] = 1;
par[u] = u;

for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
if(!vis[v]) {
LCA(v);
unite(u, v);
}
}

for(int i = hh[u]; ~i; i = anss[i].next) {
int k = anss[i].n, x = que[k].u, y = que[k].v, id = que[k].id;

if(id > Q) {
id = id-Q;
swap(x, y);
}

find(x);
find(y);

ans[id] = max(ans[id], max(up[x], down[y]));
ans[id] = max(ans[id], maxx[y] - minn[x]);
}
}

void init()
{
tot = 0;
memset(head, -1, sizeof(head));
tt = 0;
memset(h, -1, sizeof(h));
tol = 0;
memset(hh, -1, sizeof(hh));

memset(vis, 0, sizeof(vis));
memset(ans, 0, sizeof(ans));
}

int main()
{
freopen("in", "r", stdin);
while(~scanf("%d", &n)) {
for(int i = 1; i <= n; ++i) {
scanf("%d", &val[i]);
up[i] = down[i] = 0;
maxx[i] = minn[i] = val[i];
}

init();
int u, v;
for(int i = 0; i < n-1; ++i) {
scanf("%d %d", &u, &v);
addedge(u, v);
addedge(v, u);
}

scanf("%d", &Q);
for(int i = 1; i <= Q; ++i) {
scanf("%d%d", &u, &v);
addask(u, v, i);
addask(v, u, i+Q);
}

LCA(1);

for(int i = 1; i <= Q; ++i) {
printf("%d\n", ans[i]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  POJ