poj3728 The merchant

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 3761   Accepted: 1268

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

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


     这题花了很长时间啊..想明白后发现对离线tarjan算法的理解更深了,tarjan的算法核心是先处理较深的子树,然后再处理较浅的子树。这道题也是一样,因为样例很多,所以普通的暴力方法不行,这里就要结合taijan的特点,先把询问的问题分类,然后遍历到某个节点,就把最近公共祖先为这个节点的所有问题都处理完,然后再求这个节点父节点的问题。

    因为获得价值最大只有三种情况,设f为u,v的最近公共祖先,一种是起点u到f的最大区间值,一种是f到终点v的最大区间值,还有就是f到v经过的最大值减去u到f经过的最小值。所以要记录4个变量:

up[u]表示u->f的最大maxval  
down[u]表示f->u的最大maxval  
maxw[u]表示u-f的最大w[i]  
minw[u]表示u-f的最小w[i]  

然后在并查集压缩路径的时候更新。


#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
#define inf 0x7fffffff
#define maxn 50050
int first[maxn],pre[maxn],vis[maxn],w[maxn],uu[maxn],vv[maxn];
struct node{
    int to,next;
}e[2*maxn];

int h[maxn];
struct node1{
    int to,next,idx;
}question[2*maxn];

int h1[maxn];
struct node2{
    int next,idx;
}question1[2*maxn];

int answer[2*maxn];
int maxw[maxn],minw[maxn],up[maxn],down[maxn];
int tot;

int findx(int x){  //这里要用递归写法
    int i,j=x,r=x;
    if(pre[x]==x){
        return x;
    }
    int fa=pre[x];
    pre[x]=findx(fa);
    up[x]=max(max(up[fa],up[x]),maxw[fa]-minw[x]); //这里上面两个与下面两个位置不能换
    down[x]=max(max(down[fa],down[x]),maxw[x]-minw[fa]);
    minw[x]=min(minw[x],minw[fa]);
    maxw[x]=max(maxw[x],maxw[fa]);
    return pre[x];
}
void lca(int u){
    int i,j,x,y,v,idx;
    vis[u]=1;
    for(i=h[u];i!=-1;i=question[i].next){  //对问题进行分类,把祖先同为f的放在一起解决,这样递归上来的时候就会解决了
        v=question[i].to;
        idx=question[i].idx;
        if(!vis[v])continue;
        int f=findx(v);
        tot++;
        question1[tot].next=h1[f];question1[tot].idx=idx;
        h1[f]=tot;
    }
    for(i=first[u];i!=-1;i=e[i].next){
        int v=e[i].to;
        if(vis[v])continue;
        lca(v);
        pre[v]=u;
        findx(v);
    }
    for(i=h1[u];i!=-1;i=question1[i].next){
        idx=question1[i].idx;
        findx(uu[idx]);
        findx(vv[idx]);
        int t=max(up[uu[idx] ],down[vv[idx] ]);
        answer[question1[i].idx ]=max(t,maxw[vv[idx] ]-minw[uu[idx] ]);
    }

}


int main()
{
    int n,m,i,j,tot,q,c,d;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=1;i<=n;i++){
            scanf("%d",&w[i]);
            maxw[i]=minw[i]=w[i];
            up[i]=down[i]=0;
            pre[i]=i;
        }
        tot=0;
        memset(first,-1,sizeof(first));
        for(i=1;i<=n-1;i++){
            scanf("%d%d",&c,&d);
            e[i].next=first[c];e[i].to=d;
            first[c]=i;

            e[i+n-1].next=first[d];e[i+n-1].to=c;
            first[d]=i+n-1;
        }

        memset(h,-1,sizeof(h));
        scanf("%d",&q);
        for(i=1;i<=q;i++){
            scanf("%d%d",&uu[i],&vv[i]);
            int c=uu[i];
            int d=vv[i];
            question[i].to=d;question[i].idx=i;question[i].next=h[c];
            h[c]=i;

            question[i+q].to=c;question[i+q].idx=i;question[i+q].next=h[d];
            h[d]=i+q;
        }
        memset(vis,0,sizeof(vis));
        memset(h1,-1,sizeof(h1));
        tot=0;
        lca(1);
        for(i=1;i<=q;i++){
            printf("%d\n",answer[i]);
        }
    }
    return 0;
}


posted @ 2015-10-20 20:28  Herumw  阅读(103)  评论(0编辑  收藏  举报