poj3728The merchant 【倍增】【LCA】

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

倍增 LCA还是完全不会写.....

所以是看的题解

刚开始完全不能理解为什么这道题也能转换成LCA 找得到公共祖先然后呢 然后呢 然后呢

建的图相当于一个dfs树 路径是唯一的

找公共祖先t就相当于找到这条路径 公共祖先把这个路径分成了两半

最后(u, v)的答案有三种可能

1.u到t完成了买和卖

2.t到v完成了买和卖

3.在u到t某点买,t到v某点卖

因此现在需要一个up数组,up[i][j]维护i到i节点往上2^j的节点的最大差价

down数组,down[i][j]维护i到i节点往下2^j的节点的最大差价

Max数组, Max[i][j]维护i到i节点往上2^j的节点之间价格的最大值

Min数组,Min[i][j]维护i到i节点往上2^j的节点之间价格的最小值

parent数组,parent[i][0]存储每个节点的父亲,用dfs先预处理出来。用倍增的思想处理出parent[i][j]表示i往上2^j的节点

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <cstring>
#include <vector>
#include <map>
#include <set>
#include <stdio.h>
#include <queue>
#include <stack>
#define inf 0x3f3f3f3f
using namespace std;

int n, q, ecnt;
const int maxn = 50005;
int Max[maxn][20], Min[maxn][20], up[maxn][20], down[maxn][20], parent[maxn][20];
vector <int> g[maxn];
int dep[maxn],val[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;
        dep[v] = dep[u] + 1;
        parent[v][0] = u;
        Max[v][0] = max(val[v], val[u]);
        Min[v][0] = min(val[v], val[u]);
        down[v][0] = max(0, val[v] - val[u]);
        up[v][0] = max(0, val[u] - val[v]);
        dfs(v, u);
    }
}

void init()
{
    dep[1] = 1;
    memset(parent, -1, sizeof(parent));
    dfs(1, 0);
    for(int j = 1; (1 << j) <= n; j++){
        for(int i = 1; i <= n; i++){
            if(~parent[i][j - 1]){
                int k = parent[i][j - 1], a, b;
                parent[i][j] = parent[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)
{
    if(dep[a] < dep[b]) swap(a, b);
    int i;
    for(i = 0; (1 << i) <= dep[a]; i++);
    i--;
    for(int j = i; j >= 0; j--){
        if(dep[a] - (1 << j) >= dep[b]){
            a = parent[a][j];
        }
    }
    if(a == b){
        return a;
    }
    for(int j = i; j >= 0; j--){
        if(parent[a][j] != -1 && parent[a][j] != parent[b][j]){
            a = parent[a][j];
            b = parent[b][j];
        }
    }
    return parent[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 = parent[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 = parent[x][i];
        }
    }
    return ans;
}

int main()
{
    while(scanf("%d", &n) != EOF){
        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();
        scanf("%d", &q);
        while(q--){
            int u, v;
            scanf("%d%d", &u, &v);
            int t = LCA(u, v);
            int min_val, max_val, a, b;
            a = query_up(u, dep[u] - dep[t], min_val);
            b = query_down(v, dep[v] - dep[t], max_val);
            int ans = max(max(0, max_val - min_val), max(a, b));
            cout<<ans<<endl;
        }
    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/wybooooooooo/article/details/80793277