zoukankan      html  css  js  c++  java
  • POJ3728 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个点只有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;
    }
    
  • 相关阅读:
    【jQuery Case Study 1】Site:cssninjas.com
    PostgreSQL HA双机热备份配置
    PogreSQL物理备份与逻辑备份
    转:truncate,delete和drop删除表的异同
    pgsequence序列的用例
    Linux下端口占用的解决方法
    Linux下脚本的编写和执行
    schema模式的选用
    pg数据库基础备份的注意事项
    PostgreSQL VMCC多版本并发控制
  • 原文地址:https://www.cnblogs.com/keam37/p/3699189.html
Copyright © 2011-2022 走看看