【POJ3728】The merchant(LCA+並查集)(好題)

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 ≤ N, wi, Q ≤ 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

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

題目大意:給出一棵節點有值的樹,給出Q個詢問(a,b),問從a到b的最大盈利(即:先在最小值買入,再在最大值賣出)。
題解:
我們可以想一下兩點間的最大差有多少種情況。
①LCA到終點的最大值-起點到LCA的最小值
②起點到LCA的最大值-之後起點到LCA的最小值
③LCA到終點的最大值-之後終點到LCA的最小值
對於順序問題,可以開四個數組,maxv[i][j],minv[i][j]代表i到2^j的最大值和最小值。up[i][j],down[i][j]代表i到2^j的順序差的最大值,倒序差的最大值(順序是葉子結點-根節點方向,倒序相反),然後類似dp更新即可。

代碼如下:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<math.h>
#include<algorithm>
#define N 50005
#define pii make_pair
#define Y second
#define X first
using namespace std;
vector<int>g[N];
vector<pair<int,int> >qu[N],ans[N];
int res[N];
int n,q,val[N],fa[N],vis[N],u,v;
int up[N],down[N],maxv[N],minv[N];
int find(int x)
{
    if(x==fa[x]) return x;
    int f=fa[x];
    fa[x]=find(fa[x]);
    up[x]=max(up[x],max(up[f],maxv[f]-minv[x]));
    down[x]=max(down[x],max(down[f],maxv[x]-minv[f]));
    maxv[x]=max(maxv[x],maxv[f]);
    minv[x]=min(minv[x],minv[f]);
    return fa[x];
}
void LCA(int u)
{
    int len=qu[u].size();
    for(int i=0;i<len;i++)
    {
        int v=qu[u][i].Y;
        if(vis[v])
        {
            int lca=find(v);
            ans[lca].push_back(pii(u,i));
        }
    }
    vis[u]=1;fa[u]=u;
    len=g[u].size();
    for(int i=0;i<len;i++)
    {
        int v=g[u][i];
        if(vis[v]) continue;
        LCA(v);
        fa[v]=u;
    }
    len=ans[u].size();
    for(int i=0;i<len;i++)
    {
        int x=ans[u][i].X,y=qu[x][ans[u][i].Y].Y;
        int id=qu[x][ans[u][i].Y].X;
        if(id<0) 
        {
            id=-id;
            swap(x,y);
        }
        find(x);find(y);
        res[id]=max(up[y],down[x]);
        res[id]=max(res[id],maxv[x]-minv[y]);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&val[i]);
    for(int i=1;i<=n;i++) maxv[i]=minv[i]=val[i];
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&u,&v);
        qu[u].push_back(pii(-i,v));
        qu[v].push_back(pii(i,u));
    }
    memset(vis,0,sizeof(vis));
    LCA(1);
    for(int i=1;i<=q;i++) printf("%d\n",res[i]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章