POJ 3728 The merchant(在线倍增LCA)

来源:互联网 发布:淘宝下载安装2015旧版 编辑:程序博客网 时间:2024/06/05 10:09

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 55555int 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;}
原创粉丝点击