POJ 3728 The merchant


The merchant

Time Limit: 3000MS

Memory Limit: 65536K

Total Submissions: 4773

Accepted: 1654

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 chosensome paths and wants to earn as much money as possible in each path. When hemove along a path, he can choose one city to buy some goods and sell them in acity after it. The goods in all cities are the same but the prices aredifferent. Now your task is to calculate the maximum possible profit on eachpath.

Input

The first line contains N, the number ofcities.
Each of the next
N lines containswi the goods' pricein each city.
Each of the next
N-1 lines contains labels of two cities, describing aroad 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 apath. The cities are numbered from 1 toN.

1 ≤ N,wi,Q ≤ 50000

Output

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

Sample Input

4

1

5

3

2

1 3

3 2

3 4

9

1 2

1 3

1 4

2 3

2 1

2 4

3 1

3 2

3 4

Sample Output

4

2

2

0

0

0

0

2

0

 

题意:有n个城市,给出一件货物在各城市的价格,并给出各城市间的连接关系(共n-1条边,即构成一棵生成树),然后给出q个询问,每个询问有两个城市s,t,问从s到t的路径上买入卖出货物盈利的最大值(显然,要是变大,我们应该选择在价格低的地方买入,价格高的地方卖出)。

思路:我们用几个数组来维护以下值:

  • 用up数组维护从当前点到当前根节点的最大盈利。
  • 用down数组维护当前的wasd根节点到当前点的最大盈利。
  • 用Max数组维护当前点到当前根节点的最大价格。
  • 用Min数组维护当前点到当前根节点的最小价格。

实现方法依然是LCA的Tarjan算法,以上维护在并查集时实现。

LCA算法简介:传送门


#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<(b);++i)
typedef long long ll;
const int maxn= 100005;
const int mod = 475;
const ll INF = 0x3f3f3f3f;
const double eps = 1e-6;
#define rush() int T;scanf("%d",&T);while(T--)

int n,m,cnt,cnt2;
int pre[maxn];
int vis[maxn];
int head1[maxn],head2[maxn],head3[maxn];
int up[maxn],down[maxn],Max[maxn],Min[maxn];
int val[maxn],ans[maxn];


struct node
{
    int s,t,next;
}e1[maxn*2],e2[maxn*2];

struct node2
{
    int k,next;
}e3[maxn*2];

void init()
{
    cnt2=0;
    mst(vis,0);
    mst(ans,0);
    mst(head1,-1);
    mst(head2,-1);
    mst(head3,-1);
    for(int i=0;i<=n;i++)
        pre[i]=i;
}
void add1(int s,int t)
{
    e1[cnt].s=s;
    e1[cnt].t=t;
    e1[cnt].next=head1[s];
    head1[s]=cnt++;
}

void add2(int s,int t)
{
    e2[cnt].s=s;
    e2[cnt].t=t;
    e2[cnt].next=head2[s];
    head2[s]=cnt++;
}

void add3(int u,int k)
{
    e3[cnt2].k=k;
    e3[cnt2].next=head3[u];
    head3[u]=cnt2++;
}

int find(int x)
{
    if(x==pre[x])
        return x;
    int fa=pre[x];
    pre[x]=find(pre[x]);
    up[x]=max(up[x],max(up[fa],Max[fa]-Min[x]));
    down[x]=max(down[x],max(down[fa],Max[x]-Min[fa]));
    Max[x]=max(Max[x],Max[fa]);
    Min[x]=min(Min[x],Min[fa]);
    return pre[x];
}

void join(int a,int b)
{
    int A,B;
    A=find(a);
    B=find(b);
    if(A!=B)
        pre[B]=A;
}


void Tarjan(int now)
{
    vis[now]=1;
    for(int i=head1[now];i!=-1;i=e1[i].next)
    {
        int t=e1[i].t;
        if(vis[t]==0)
        {
            Tarjan(t);
            join(now,t);
        }
    }
    for(int i=head2[now];i!=-1;i=e2[i].next)
    {
        int t=e2[i].t;
        if(vis[t]==1)
        {
            int lca=find(t);
            add3(lca,i);
        }
    }
    for(int i=head3[now];i!=-1;i=e3[i].next)
    {
        int k=e3[i].k;
        int s=e2[k].s;
        int t=e2[k].t;
        if(k&1)              //k--;
        {
            k^=1;
            swap(s,t);      //如果是反向边要交换起点和终点
        }
        k/=2;
        find(s);
        find(t);
        ans[k]=max(Max[t]-Min[s],max(up[s],down[t]));
    }
}

int main()
{
    int x;
    int u,v;
    while(~scanf("%d",&n))
    {
        init();
        cnt=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            up[i]=down[i]=0;
            Max[i]=Min[i]=x;
        }
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            add1(u,v);
            add1(v,u);
        }
        cnt=0;
        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            add2(u,v);
            add2(v,u);
        }
        Tarjan(1);
        for(int i=0;i<m;i++)
        {
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}



 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值