POJ 3728:The merchant LCA

来源:互联网 发布:javascript排序 编辑:程序博客网 时间:2024/05/22 10:37

The merchant
Time Limit: 3000MS Memory Limit: 65536KTotal Submissions: 3950 Accepted: 1333

Description

There are N cities in a country, and there is one and only one simple path between each pair of cities. A merchant has chosen some paths and wants to earn as much money as possible in each path. When he move along a path, he can choose one city to buy some goods and sell them in a city after it. The goods in all cities are the same but the prices are different. Now your task is to calculate the maximum possible profit on each path.

Input

The first line contains N, the number of cities.
Each of the next N lines contains wi the goods' price in each city.
Each of the next N-1 lines contains labels of two cities, describing a road between the two cities.
The next line contains Q, the number of paths.
Each of the next Q lines contains labels of two cities, describing a path. The cities are numbered from 1 to N.

1 ≤ NwiQ ≤ 50000 

Output

The output contains Q lines, each contains the maximum profit of the corresponding path. If no positive profit can be earned, output 0 instead.

Sample Input

41 5 3 21 33 23 491 21 31 42 32 12 43 13 23 4

Sample Output

422000020

题意是给出一棵树,树上节点有对应货物的价值,问从i节点走到j节点,买一个货物,再卖一个货物,最多能赚多少钱。赚不到钱输出0。

这道题整整折磨我三天,从早上到晚上,WA了二十多次,自己编了各种数据测,嘴上起了一圈泡。。。到最后上网上找了一份代码http://blog.csdn.net/xingyeyongheng/article/details/20402603和他数据拍,当然,最后A的时候终于也算是搞明白了自己犯的各种错误。

总结来说的话,感觉通过这道题,把离线LCA的tarjan算是搞懂一些,然后也明白自己在期间犯的各种错误。

这个题求从u到v的路径的最大收益。第一步很好理解,找到LCA,那么结果只可能有三种情况,u到LCA的最大收益,LCA到u的最大收益,abs(u到LCA的最小值-LCA到v的最大值)。

所以总的来说,对于每一个点x,要维护的就是x到LCA的最大最小值,x到LCA的最大差值,LCA到x的最大差值。这四个值,然后离线求询问。

自己犯的第一个错误,需要把所有要求的询问离线处理,这块受之前做的1986影响了,思维实在太窄,拿数据拍出来才知道自己犯错了,每一个u,v询问这块必须是两者都被扫描完结束之后在LCA(u,v)那块处理,只在v扫描之后,在u那里是错误的,因为u的信息还没有完全,即想要找u的话,还需要向上爬到LCA(u,v)。

自己犯的第二个错误,更新四个信息时,之前自己错误的写法是:

up_w[x] = max(up_w[x], up_w[father]);down_w[x] = min(down_w[x], down_w[father]);up[x] = max(max(up[x], up[father]), up_w[father] - pri[x]);down[x] = max(max(down[x], down[father]), pri[x] - down_w[father]);
在每一个getfa函数内部down_w[x]相当于表示x到当前节点的最小值,所以为了表示i到当前父节点的最大差值,需要把之前路径上的最小值都算上,即down_w[x],而不是pri[x],这块自己实在太二逼,想得太简单了。

                up[x] = max(max(up[x], up[father]), up_w[father] - down_w[x]);down[x] = max(max(down[x], down[father]), up_w[x] - down_w[father]);up_w[x] = max(up_w[x], up_w[father]);down_w[x] = min(down_w[x], down_w[father]);
代码:

#pragma warning(disable:4996)#include <iostream>#include <functional>#include <algorithm>#include <cstring>#include <vector>#include <string>#include <cstdio>#include <cmath>#include <queue>#include <stack>#include <deque>#include <set>#include <map>using namespace std;typedef long long ll;#define INF 0x3fffffffffffffffconst ll mod = 1e9 + 7;const int maxn = 4e5 + 5;struct ed{int id;int to;int next;}edge[maxn], qedge[maxn], q2edge[maxn];int n, edgen, qedgen, q2edgen, qnum;int pri[maxn], v[maxn], uu[maxn], vv[maxn];int head[maxn], qhead[maxn], q2head[maxn], f[maxn], vis[maxn], ans[maxn];int up[maxn], down[maxn], up_w[maxn], down_w[maxn];void addedge(int from, int to){edgen++;edge[edgen].to = to;edge[edgen].next = head[from];head[from] = edgen;}void addqedge(int from, int to, int id){qedgen++;qedge[qedgen].to = to;qedge[qedgen].id = id;qedge[qedgen].next = qhead[from];qhead[from] = qedgen;}void addq2edge(int from, int to, int id){q2edgen++;q2edge[q2edgen].to = to;q2edge[q2edgen].id = id;q2edge[q2edgen].next = q2head[from];q2head[from] = q2edgen;}void init(){edgen = 0;qedgen = 0;q2edgen = 0;memset(q2head, -1, sizeof(q2head));memset(qhead, -1, sizeof(qhead));memset(head, -1, sizeof(head));memset(q2edge, -1, sizeof(q2edge));memset(qedge, -1, sizeof(qedge));memset(edge, -1, sizeof(edge));memset(ans, 0, sizeof(ans));memset(v, 0, sizeof(v));memset(vis, 0, sizeof(vis));memset(f, 0, sizeof(f));memset(up, 0, sizeof(up));memset(down, 0, sizeof(down));memset(up_w, 0, sizeof(up_w));memset(down_w, 0, sizeof(down_w));}void input(){int i, j, k;int u, v;for (i = 1; i <= n; i++){scanf("%d", &pri[i]);down_w[i] = up_w[i] = pri[i];}for (i = 1; i <= n - 1; i++){scanf("%d%d", &u, &v);addedge(u, v);addedge(v, u);}scanf("%d", &qnum);for (i = 1; i <= qnum; i++){scanf("%d%d", &uu[i], &vv[i]);addqedge(uu[i], vv[i], i);addqedge(vv[i], uu[i], i);}}int getfa(int x){if (f[x] == x){return x;}else{int father = f[x];f[x] = getfa(f[x]);up[x] = max(max(up[x], up[father]), up_w[father] - down_w[x]);down[x] = max(max(down[x], down[father]), up_w[x] - down_w[father]);up_w[x] = max(up_w[x], up_w[father]);down_w[x] = min(down_w[x], down_w[father]);return f[x];}}//up[i]表示i节点到祖先节点的差值最大值//down[i]表示祖先节点到i的差值最大值//up_w[i]表示i到祖先节点的值的最大值//down_w[i]表示祖先节点到i的值的最小值void tarjan(int x){v[x] = 1;f[x] = x;int i, k, id, fa;for (i = qhead[x]; i != -1; i = qedge[i].next){k = qedge[i].to;id = qedge[i].id;if (v[k] == 0)continue;fa = getfa(k);addq2edge(fa, k, id);}for (i = head[x]; i != -1; i = edge[i].next){k = edge[i].to;if (v[k])continue;tarjan(k);f[k] = x;}for (i = q2head[x]; i != -1; i = q2edge[i].next){k = q2edge[i].to;id = q2edge[i].id;getfa(uu[id]);getfa(vv[id]);//x到kans[id] = max(max(up[uu[id]], down[vv[id]]), up_w[vv[id]] - down_w[uu[id]]);}}void solve(){int i;tarjan(1);for (i = 1; i <= qnum; i++){//printf("%d %d\n", i, ans[i]);printf("%d\n", ans[i]);}}int main(){#ifndef ONLINE_JUDGE  freopen("i.txt", "r", stdin);freopen("o.txt", "w", stdout);#endif while (scanf("%d", &n) != EOF){init();input();solve();}//system("pause");return 0;}





0 0
原创粉丝点击