码迷,mamicode.com
首页 > 其他好文 > 详细

「题解」poj 3728 The merchant

时间:2020-08-29 15:18:55      阅读:56      评论:0      收藏:0      [点我收藏+]

标签:之间   algo   技术   ++i   def   ant   题解   ble   简化   

题目

The merchant

简化题意

给你一棵树,点有点权,到达一个点你可以花费该点的点权买入一个东西,然后在另一个点把这个东西卖出(卖出的时候手上必须有东西),只能买入卖出一次,问你从一个点 \(u\) 到一个点 \(v\) 的路径上能获得的最大收益。

思路

倍增。
除了正常倍增需要维护的东西还要维护下面这些:
\(maxx[i][j]\),表示在 \(i\) 到从 \(i\)\(2 ^ j\) 步到达的那个点之间的路径上的最大点权。
\(minn[i][j]\),表示在 \(i\) 到从 \(i\)\(2 ^ j\) 步到达的那个点之间的路径上的最小点权。
\(up[i][j]\),表示在 \(i\) 到从 \(i\)\(2 ^ j\) 步到达的那个点之间的路径上按 \(i \rightarrow i ^ j\) 的顺序能获得的最大收益。
\(down[i][j]\),表示在 \(i\) 到从 \(i\)\(2 ^ j\) 步到达的那个点之间的路径上按 \(i ^ j \rightarrow i\) 的顺序能获得的最大收益。
对于 \(u \rightarrow v\),进行分类讨论,如下图。
技术图片
\(t\)\(u\)\(v\) 的最近公共祖先。

  • 可能在 \(u \rightarrow t\) 的路径上获得最大收益,即在 \(u \rightarrow t\) 上买卖。
  • 可能在 \(t \rightarrow v\) 的路径上获得最大收益,即在 \(t \rightarrow v\) 上买卖。
  • 可能在 \(u \rightarrow t\) 上买,在 \(t \rightarrow v\) 上卖。

Code

#include <cstdio>
#include <cstring>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXN 50001
#define inf 2147483647

int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }

int n, m, pthn, a[MAXN], head[MAXN];
int lg[MAXN], fa[MAXN][21], dep[MAXN];
int maxx[MAXN][21], minn[MAXN][21], up[MAXN][21], down[MAXN][21];
struct Edge {
	int next, to;
}pth[MAXN << 1];

void add(int from, int to) {
	pth[++pthn].to = to, pth[pthn].next = head[from];
	head[from] = pthn;
}

void dfs(int u, int father) {
	maxx[u][0] = max(a[u], a[father]);
	minn[u][0] = min(a[u], a[father]);
	up[u][0] = max(0, a[father] - a[u]);
	down[u][0] = max(0, a[u] - a[father]);
	fa[u][0] = father, dep[u] = dep[father] + 1;
	for (int i = head[u]; i; i = pth[i].next) {
		int x = pth[i].to;
		if (x != father) dfs(x, u);
	}
}

int lca(int x, int y) {
	if (dep[y] > dep[x]) std::swap(x, y);
	while (dep[x] > dep[y]) {
		x = fa[x][lg[dep[x] - dep[y]] - 1];
	}
	if (x == y) return x;
	for (int k = lg[dep[x]] - 1; k >= 0; --k) {
		if (fa[x][k] != fa[y][k]) {
			x = fa[x][k];
			y = fa[y][k];
		}
	}
	return fa[x][0];
}

int getup(int s, int t, int &min_) {
	int up_ = 0;
	while (dep[s] > dep[t]) {
		int step = lg[dep[s] - dep[t]] - 1;
		up_ = max(up_, max(up[s][step], maxx[s][step] - min_));
		min_ = min(min_, minn[s][step]);
		s = fa[s][step];
	}
	return up_;
}

int getdown(int s, int t, int &max_) {
	int down_ = 0;
	while (dep[s] > dep[t]) {
		int step = lg[dep[s] - dep[t]] - 1;
		down_ = max(down_, max(down[s][step], max_ - minn[s][step]));
		//std::cout << max_ << " " << s << " " << step << " " << maxx[s][step] << ‘\n‘;
		max_ = max(max_, maxx[s][step]);
		s = fa[s][step];
		//std::cout << max_ << " " << s << " " << step << " " << maxx[s][step] << ‘\n‘;
	}
	return down_;
}

int main() {
	//freopen("a.txt", "w", stdout);
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	for (int i = 1, u, v; i < n; ++i) {
		scanf("%d %d", &u, &v);
		add(u, v), add(v, u);
	}
	for (int i = 1; i <= n; ++i) {
		lg[i] = lg[i - 1] + ((1 << lg[i - 1]) == i);
	}
	dfs(1, 0);
	for (int j = 1; (1 << j) <= n; ++j) {
		for (int i = 1; i <= n; ++i) {
			int temp = fa[i][j - 1];
			fa[i][j] = fa[temp][j - 1];
			maxx[i][j] = max(maxx[i][j - 1], maxx[temp][j - 1]);
			minn[i][j] = min(minn[i][j - 1], minn[temp][j - 1]);
			up[i][j] = max(max(up[i][j - 1], up[temp][j - 1]), maxx[temp][j - 1] - minn[i][j - 1]);
			down[i][j] = max(max(down[temp][j - 1], down[i][j - 1]), maxx[i][j - 1] - minn[temp][j - 1]);
		}
	}
	scanf("%d", &m);
	for (int i = 1, u, v; i <= m; ++i) {
		scanf("%d %d", &u, &v);
		int l = lca(u, v), min_ = inf, max_ = 0;
		int upmx = getup(u, l, min_);
		int downmx = getdown(v, l, max_);
		//std::cout << u << " " << v << " " << l << ‘\n‘;
		//std::cout << upmx << " " << downmx << " " << min_ << " " << max_ << ‘\n‘;
		int ans = max(max(upmx, downmx), max_ - min_);
		printf("%d\n", ans);
	}
	return 0;
}

「题解」poj 3728 The merchant

标签:之间   algo   技术   ++i   def   ant   题解   ble   简化   

原文地址:https://www.cnblogs.com/poi-bolg-poi/p/13563573.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!