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个点只有n-1条边,又保证每两个点之间只有一条路径,明显是一颗树。
题目就变成了找到两个点之间的路径,求出路径后再要求出最大收益便非常简单。
求一颗树中两点的路径可以用最近公共祖先算法
还可以在求LCA的同时将最大收益更新出来,只需要记录几个值即可。
如果是要边找边求的话使用离线的tarjan算法,只要记录几个值,便可。
由于对倍增法不太熟悉所以用这道题来熟悉倍增法
代码在这里
#include <cstdio> #include <vector> #define INF 55555 using namespace std; struct record { int x, upMax, doMax, pMin, pMax; }; int nPrice[INF], nSnode[INF]; int nDeep[INF]; record pNode[INF][18]; bool vis[INF]; const int Pow = 17; vector<int> g[INF]; //dfs 求出所需值 void dfs (int u, int fa) { vis[u] = true, nDeep[u] = nDeep[fa] + 1, pNode[u][0].x = fa; //pNode记录从节点向上2^j个节点中最大收益upMAX, //从最上节点到u的最大收益domax,和最大价格最小价格pMax,pMin pNode[u][0].pMin = min (nPrice[u], nPrice[fa]); pNode[u][0].pMax = max (nPrice[u], nPrice[fa]); pNode[u][0].upMax = max (0, nPrice[fa] - nPrice[u]),; pNode[u][0].doMax = max (nPrice[u] - nPrice[fa], 0); //dp更新pNode for (int i = 1; i <= Pow; i++) { int j = pNode[u][i - 1].x; pNode[u][i].x = pNode[j][i - 1].x; pNode[u][i].pMin = min (pNode[u][i - 1].pMin, pNode[j][i - 1].pMin); pNode[u][i].pMax = max (pNode[u][i - 1].pMax, pNode[j][i - 1].pMax); pNode[u][i].upMax = max (pNode[u][i - 1].upMax, pNode[j][i - 1].upMax); pNode[u][i].upMax = max (pNode[u][i].upMax, pNode[j][i - 1].pMax - pNode[u][i - 1].pMin); pNode[u][i].doMax = max (pNode[u][i - 1].doMax, pNode[j][i - 1].doMax); pNode[u][i].doMax = max (pNode[u][i].doMax, pNode[u][i - 1].pMax - pNode[j][i - 1].pMin); }; int nSize = g[u].size(); for (int i = 0; i < nSize; i++) { int v = g[u][i]; if (v == fa || vis[v]) continue; dfs (v, u); } } int aMin, bMax, upDmax, doDmax, ans; //更新doDmax void makeb (int i, int &b) { doDmax = max (doDmax, pNode[b][i].doMax),; doDmax = max (doDmax, bMax - pNode[b][i].pMin); bMax = max (bMax, pNode[b][i].pMax); b = pNode[b][i].x; } //更新upDmax void makea (int i, int &a) { upDmax = max (upDmax, pNode[a][i].upMax),; upDmax = max (upDmax, pNode[a][i].pMax - aMin); aMin = min (aMin, pNode[a][i].pMin); a = pNode[a][i].x; } int bzlca (int a, int b) { aMin = nPrice[a], bMax = nPrice[b] ; upDmax = doDmax = 0; //将a,b置于同一层 //将b向上提,更新向下到b的最大收益doDmax if (nDeep[a] < nDeep[b]) for (int del = nDeep[b] - nDeep[a], i = 0; i < Pow; i++) if (del & (1 << i) ) makeb (i, b); //将a向上提,更新从a向上到的最大收益upDmax if (nDeep[a] > nDeep[b]) for (int del = nDeep[a] - nDeep[b], i = 0; i < Pow; i++) if (del & (1 << i) ) makea (i, a); //找到a,b的最近公共祖先,同时更新从a向上到祖先的最大收益 //从祖先向下到b的最大收益 if (a != b) { for (int i = Pow ; i >= 0; i--) if (pNode[a][i].x != pNode[b][i].x) makea (i, a), makeb (i, b); makea (0, a), makeb (0, b); } ans = max (doDmax, upDmax), ans = max (ans, bMax - aMin); return ans; } int main() { int x, y, n, m; scanf ("%d", &n); for (int i = 1; i <= n; i++) scanf ("%d", &nPrice[i]); for (int i = 1; i < n; i++) { scanf ("%d %d", &x, &y); g[x].push_back (y), g[y].push_back (x); } dfs (1, 1); scanf ("%d", &m); for (int i = 1; i <= m; i++) { scanf ("%d %d", &x, &y); printf ("%d ", bzlca (x, y) ); } return 0; }