POJ 3728 The merchant(在线倍增LCA)

Description
n个城市构成一棵树,每个城市都有一种商品有一个固定的价格,一个商人要从一个城市到另一个城市,他会在路途中选取一个城市购买这种商品然后在之后的某个城市卖掉以赚取差价,问最大差价
Input
第一行一整数n表示城市个数,之后n个整数val[i]表示第i个城市该种商品的价格,之后n-1行每行两个整数u和v表示u城市和v城市有路径,然后输入一整数q表示查询数,每次查询输入两个整数u和v表示商人从u到v路途中可以赚取的最大差价(1<=n,val[i],q<=50000)
Output
对于每组查询输出一个答案
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
Solution
Max[i][j],Min[i][j]分别表示i节点到i节点往上2^j个节点的路径上点权最大值和最小值,up[i][j]表示i节点到i节点往上2^j节点路径上可以赚取的最大差价,down[i][j]表示节点往上2^j节点到i路径上可以赚取的最大差价,p[i][j]表示i节点的第2^j层父亲节点,在线倍增维护这五个值,那么从u到v的路径上可以赚取的路径最大值有三种情况:
1.从u到lca(u,v)的up值
2.lca(u,v)到v的Max减去从u到lca(u,v)的Min
3.lca(u,v)到v的down值
选取一个最大值即为答案
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 55555
int n,q,p[maxn][20],deep[maxn],val[maxn];
int down[maxn][20],up[maxn][20],Max[maxn][20],Min[maxn][20];
vector<int>g[maxn];
void dfs(int u,int fa)
{
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i];
        if(v==fa)continue;
        deep[v]=deep[u]+1;
        p[v][0]=u;
        Max[v][0]=max(val[u],val[v]);
        Min[v][0]=min(val[u],val[v]);
        down[v][0]=max(0,val[v]-val[u]);
        up[v][0]=max(0,val[u]-val[v]);
        dfs(v,u);
    }
}
void init(int n)
{
    deep[1]=1;
    memset(p,-1,sizeof(p));
    dfs(1,0);
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i<=n;i++)
            if(~p[i][j-1])
            {
                int k=p[i][j-1],a,b;
                p[i][j]=p[k][j-1];
                Max[i][j]=max(Max[i][j-1],Max[k][j-1]);
                Min[i][j]=min(Min[i][j-1],Min[k][j-1]);
                a=max(0,Max[i][j-1]-Min[k][j-1]),b=max(down[i][j-1],down[k][j-1]);
                down[i][j]=max(a,b);
                a=max(0,Max[k][j-1]-Min[i][j-1]),b=max(up[i][j-1],up[k][j-1]);
                up[i][j]=max(a,b);
            }
}
int lca(int a,int b)
{
    int i,j;
    if(deep[a]<deep[b])swap(a,b);
    for(i=0;(1<<i)<=deep[a];i++);
    i--;
    for(j=i;j>=0;j--)
        if(deep[a]-(1<<j)>=deep[b])
            a=p[a][j];
    if(a==b) return a;
    for(j=i;j>=0;j--)
    {
        if(p[a][j]!=-1&&p[a][j]!=p[b][j])
        {
            a=p[a][j];
            b=p[b][j];
        }
    }
    return p[a][0];
}
int query_down(int x,int k,int &max_val)
{
    int ans=0;
    max_val=0;
    for(int i=18;i>=0;i--)
        if(k&(1<<i))
        {
            ans=max(ans,down[x][i]);
            ans=max(ans,max_val-Min[x][i]);
            max_val=max(max_val,Max[x][i]);
            x=p[x][i];
        }
    return ans;
}
int query_up(int x,int k,int &min_val)
{
    int ans=0;
    min_val=INF;
    for(int i=18;i>=0;i--)
        if(k&(1<<i))
        {
            ans=max(ans,up[x][i]);
            ans=max(ans,Max[x][i]-min_val);
            min_val=min(min_val,Min[x][i]);
            x=p[x][i];
        }
    return ans;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)scanf("%d",&val[i]);
        for(int i=1;i<=n;i++)g[i].clear();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].push_back(v),g[v].push_back(u);
        }
        init(n);
        scanf("%d",&q);
        while(q--)
        {
            int u,v,t;
            scanf("%d%d",&u,&v);
            t=lca(u,v);
            int min_val,max_val,a,b;
            a=query_up(u,deep[u]-deep[t],min_val);
            b=query_down(v,deep[v]-deep[t],max_val);
            int ans=max(max(0,max_val-min_val),max(a,b));
            printf("%d\n",ans);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值