POJ 3728 The merchant
http://poj.org/problem?id=3728
https://vjudge.net/problem/POJ-3728
問題概要
-
ある国には$N$個の都市があり、各都市のペアの間には1つの単純パスしかない。(都市の繋がりは木として表される)
-
物価が都市によって異なり、ある商品の都市$i$での値段は$w_i$である。
-
$Q$個のクエリに答えよ
- クエリ $a_i, b_i$ : 都市$a_i$から都市$b_i$へ移動する際、そのパス上のある都市で商品を購入し、それ以降のある都市で売却する。$\max(得られる利益の最大値, 0)$を出力せよ
制約
- $1\leq N,w_i,Q\leq5\times10^4$
解法メモ
- LCAをダブリングで求めるときに、一緒に$(その区間w_iの最大値, その区間のw_iの最小値,その区間内で得られる利益の最大値)$を分割統治で求める。これのマージは可換でないので左右からの計算結果を持つ必要がある。
- 計算量は準備に$O(N\log N)$, クエリあたり$O(\log N)$
HL分解+セグメント木(or Disjoint Sparse Table)で実装する方がが楽そう
実装例
HL分解で実装したらTLEが取れなかったのでダブリング解法。TLギリギリなのであまりよい実装ではなさそう
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <stack>
#include <vector>
typedef long long ll;
#define rep(i, n) for (ll i = 0, i##_len = (n); i < i##_len; ++i)
#define inf int(2e9)
using namespace std;
struct S {
int maxW, minW, maxVal;
S(int maxW = 0, int minW = 0, int maxVal = 0) : maxW(maxW), minW(minW), maxVal(maxVal) {}
};
S e() {
S res;
res.maxW = -inf;
res.minW = inf;
res.maxVal = -inf;
return res;
}
S op(S a, S b) {
S res;
res.maxW = max(a.maxW, b.maxW);
res.minW = min(a.minW, b.minW);
res.maxVal = max(b.maxW - a.minW, max(a.maxVal, b.maxVal));
return res;
}
template <typename edge>
struct LCA {
private:
const vector<vector<edge> > &G;
int root, logV;
vector<vector<int> > _parent;
vector<int> _depth;
vector<vector<S> > data, dataRev; // *
void dfs() {
_parent.at(0).at(root) = -1;
_depth.at(root) = 0;
stack<int, vector<int> > s;
s.push(root);
while (!s.empty()) {
int cur = s.top();
s.pop();
for (int i = 0; i < G.at(cur).size(); i++) {
const edge &e = G.at(cur).at(i);
if (e.to != _parent.at(0).at(cur)) {
_parent.at(0).at(e.to) = cur;
_depth.at(e.to) = _depth.at(cur) + 1;
s.push(e.to);
}
}
}
}
public:
LCA(const vector<vector<edge> > &G, const vector<S> &w) : G(G), root(0) {
logV = 1;
int _v = 1;
while (_v < int(G.size())) {
_v *= 2;
logV++;
}
_parent = vector<vector<int> >(logV, vector<int>(G.size()));
_depth = vector<int>(G.size());
dfs();
data = vector<vector<S> >(logV, vector<S>(G.size(), e()));
dataRev = vector<vector<S> >(logV, vector<S>(G.size(), e()));
rep(i, G.size()) {
data[0][i] = w[i];
dataRev[0][i] = w[i];
}
for (int k = 0; k < logV - 1; k++) {
for (int v = 0; v < int(G.size()); v++) {
if (_parent.at(k).at(v) < 0) {
_parent.at(k + 1).at(v) = -1;
data[k + 1][v] = e();
dataRev[k + 1][v] = e();
} else {
_parent.at(k + 1).at(v) = _parent.at(k).at(_parent.at(k).at(v));
data[k + 1][v] = op(data[k][v], data[k][_parent[k][v]]);
dataRev[k + 1][v] = op(dataRev[k][_parent[k][v]], dataRev[k][v]);
}
}
}
}
int query(int u, int v) {
if (_depth.at(u) > _depth.at(v)) swap(u, v);
for (int k = 0; k < logV; k++) {
if ((_depth.at(v) - _depth.at(u)) >> k & 1) {
v = _parent.at(k).at(v);
}
}
if (u == v) return u;
for (int k = logV - 1; k >= 0; k--) {
if (_parent.at(k).at(u) != _parent.at(k).at(v)) {
u = _parent.at(k).at(u);
v = _parent.at(k).at(v);
}
}
return _parent.at(0).at(u);
}
S prod(int u, int v) {
bool isRev = false;
if (_depth.at(u) > _depth.at(v)) {
swap(u, v);
isRev = true;
}
S resHead = e(), resTail = e();
for (int k = 0; k < logV; k++) {
if ((_depth.at(v) - _depth.at(u)) >> k & 1) {
if (isRev) resHead = op(resHead, data[k][v]);
else resTail = op(dataRev[k][v], resTail);
v = _parent.at(k).at(v);
}
}
if (u == v) {
if (isRev) return op(resHead, data[0][u]);
else return op(data[0][u], resTail);
}
for (int k = logV - 1; k >= 0; k--) {
if (_parent.at(k).at(u) != _parent.at(k).at(v)) {
if (isRev) {
resHead = op(resHead, data[k][v]);
resTail = op(dataRev[k][u], resTail);
} else {
resHead = op(resHead, data[k][u]);
resTail = op(dataRev[k][v], resTail);
}
u = _parent.at(k).at(u);
v = _parent.at(k).at(v);
}
}
if (isRev) {
resHead = op(resHead, data[0][v]);
resTail = op(data[0][u], resTail);
} else {
resHead = op(resHead, data[0][u]);
resTail = op(dataRev[0][v], resTail);
}
return op(resHead, op(data[0][_parent.at(0).at(u)], resTail));
}
const vector<vector<int> > &parent() { return _parent; }
const vector<int> &depth() { return _depth; }
};
struct edge {
int to;
edge(int to) : to(to) {}
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin >> n;
vector<S> w(n);
rep(i, n) {
int ww;
cin >> ww;
w[i] = S(ww, ww, 0);
}
vector<vector<edge> > G(n);
rep(i, n - 1) {
int u, v;
cin >> u >> v;
u--, v--;
G[u].push_back(edge(v));
G[v].push_back(edge(u));
}
LCA<edge> lca(G, w);
int q;
cin >> q;
rep(i, q) {
int u, v;
cin >> u >> v;
u--, v--;
cout << lca.prod(u, v).maxVal << endl;
}
}