POJ3728(The merchant)

The merchant

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

題意

確實有N一個國家的城市,每一對城市之間只有一條簡單的道路。一位商人選擇了一些道路並希望在每條道路上儘可能多地賺到錢。當他沿着一條路走時他可以選擇一座城市購買一些商品然後再在城市裏出售,(不能走回頭路),問最多正賺多少差價。

思路

在線倍增LCA + dp,維護五個參數:

  1. f[x][i]表示i節點上跳2^j次的祖先節點
  2. maxv[i][j] 表示從i 節點 到2^j的節點最大權值
  3. minv[i][j] 表示從i 節點 到2^j的節點最小權值
  4. up[i][j]表示i節點到2^j節點的最大差價
  5. down[i][j]表示2^j節點到i節點的最大差價

維護完這五個參數之後,查詢x 和 y兩點的最大差價求出 x -> LCA的最大差價(ans1),x -> LCA的最小權值(min_ans),y - > LCA的最大差價(ans2),y - > LCA的最大權值(max_ans)。最後得到答案就是 max(ans1,ans2),max(max_ans-min_ans,0)四個答案裏面最大的那個。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int inf = 0x3f3f3f3f; 
const int maxn = 50005;
const int maxd = 19;
struct edge{
	int to;
	int next;
}e[maxn<<1];
int a[maxn];
int dep[maxn];
int head[maxn];
int maxv[maxn][20];
int minv[maxn][20];
int up[maxn][20];
int down[maxn][20];
int f[maxn][20];
int tot;
inline void clear_set()
{
	memset(head,-1,sizeof(head));
	memset(f,0,sizeof(f));
	memset(dep,0,sizeof(dep));
	memset(maxv,0,sizeof(maxv));
	memset(minv,0,sizeof(minv));
	memset(up,0,sizeof(up));
	memset(down,0,sizeof(down));
}
inline void addedge(int x,int y)
{
	e[tot].to = y;
	e[tot].next = head[x];
	head[x] = tot++;
}
inline void dfs(int x,int fx)
{
	for(int i = head[x];~i;i = e[i].next){
		int y = e[i].to;
		if(y == fx)		continue;
		dep[y] = dep[x] + 1;
		f[y][0] = x;					
		minv[y][0] = min(a[x],a[y]);	
		maxv[y][0] = max(a[x],a[y]);
		up[y][0] = max(0,a[x]-a[y]);
		down[y][0] = max(0,a[y]-a[x]);
		dfs(y,x); 
	}
}
int LCA(int x,int y)
{
	if(dep[x] < dep[y])		swap(x,y);
	int d = dep[x] - dep[y];
	for(int i = 0;i <= maxd;i++){
		if(((1<<i)&d)){
			x = f[x][i];
		}
	}
	if(x == y)		return x;
	for(int i = maxd;i >= 0;i--){
		if(f[x][i] != f[y][i]){
			x = f[x][i];
			y = f[y][i];
		}
	}
	return f[x][0];
}
int query_u(int x,int d,int &min_ans)
{
	int ans = 0;
	min_ans = inf;
	for(int i = 0;i <= maxd;i++){
		if(((1<<i)&d)){
			ans = max(ans,up[x][i]);
			ans = max(ans,maxv[x][i]-min_ans);
			min_ans = min(min_ans,minv[x][i]);
			x = f[x][i];
		}
	}
	return ans;				
} 
int query_d(int x,int d,int &max_ans)
{
	int ans = 0;
	max_ans = 0;
	for(int i = 0;i <= maxd;i++){
		if(((1<<i)&d)){
			ans = max(ans,down[x][i]);
			ans = max(ans,max_ans-minv[x][i]);
			max_ans = max(max_ans,maxv[x][i]);
			x = f[x][i];
		}
	}
	return ans;
} 
int main()
{
	int n,m;
	while(~scanf("%d",&n)){
		tot = 0;clear_set();
		for(int i = 1;i <= n;i++){
			scanf("%d",&a[i]);
		}
		int x,y;
		for(int i = 1;i < n;i++){
			scanf("%d%d",&x,&y);
			addedge(x,y);addedge(y,x);
		}
		dep[1] = 1;dfs(1,0);
		for(int j = 1;j <= maxd;j++){
			for(int i = 1;i <= n;i++){
				int fx = f[i][j-1];
				f[i][j] = f[fx][j-1];			
				maxv[i][j] = max(maxv[i][j-1],maxv[fx][j-1]);		//更新最大值 
				minv[i][j] = min(minv[i][j-1],minv[fx][j-1]);		//更新最小值 
				int a = max(up[i][j-1],up[fx][j-1]);				//[i,2^(j-1)],[fx,2^(j-1)]最大 
				int b = max(0,maxv[fx][j-1]-minv[i][j-1]);			//[fx,2^(j-1)]最大權 -  [i,2^(j-1)]最小 
				up[i][j] = max(a,b);								//up是維護i節點到 2^j節點的最大     (x -> LCA) 
				a = max(down[i][j-1],down[fx][j-1]);				//[i,2^(j-1)],[fx,2^(j-1)]最大
				b = max(0,maxv[i][j-1]-minv[fx][j-1]);				//[i,2^(j-1)]最大權 -  [fx,2^(j-1)]最小權
				down[i][j] = max(a,b);								//down是維護2^j節點到 i節點的最大   (LCA -> y) 
			}
		}
		scanf("%d",&m);
		while(m--){
			scanf("%d%d",&x,&y);
			int r = LCA(x,y);
			int min_ans,max_ans;
			int ans1 = query_u(x,dep[x]-dep[r],min_ans);			 
			int ans2 = query_d(y,dep[y]-dep[r],max_ans);
			int ans = max(max(ans1,ans2),max(max_ans-min_ans,0));
			printf("%d\n",ans);
		}
	}
	return 0;
}

願你走出半生,歸來仍是少年~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章