题意:
给定N≤5×104的一棵树,Q≤5×104次查询
每个点都有一个价格,问(u,v)路径获得的最大利润(某个点买入某个点卖出),无利润输出0
分析:
显然有三种情况,u→lca,lca→v,u→v获得最大利润
那么维护up[u]:u→lca获得的最大利润
down[u]:lca→u获得的最大利润
maxw[u]:lca→u的w最大值
minw[u]:u→lca的w最小值
显然答案是ans(u,v)=max(max(up[u],down[v]),maxw[v]−minw[u]);
这个可以tarjan搞
代码:
//
// Created by TaoSama on 2015-11-10
// Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
int n, q, ans[N];
int maxw[N], minw[N], up[N], down[N];
int cnt;
struct Edge {
int v, nxt;
} E[N];
int headE[N];
void addEdge(int u, int v) {
E[cnt] = (Edge) {v, headE[u]};
headE[u] = cnt++;
E[cnt] = (Edge) {u, headE[v]};
headE[v] = cnt++;
}
struct Query {
int u, v, nxt;
} Q[N];
int headQ[N];
void addQuery(int u, int v) {
Q[cnt] = (Query) {u, v, headQ[u]};
headQ[u] = cnt++;
Q[cnt] = (Query) {v, u, headQ[v]};
headQ[v] = cnt++;
}
struct LCA {
int id, nxt;
} L[N];
int headL[N];
void addLCA(int lca, int id) {
L[cnt] = (LCA) {id, headL[lca]};
headL[lca] = cnt++;
}
int ancestor[N], vis[N];
int find(int u) {
if(ancestor[u] == u) return u;
int f = ancestor[u];
ancestor[u] = find(ancestor[u]);
up[u] = max(max(up[u], up[f]), maxw[f] - minw[u]);
down[u] = max(max(down[u], down[f]), maxw[u] - minw[f]);
maxw[u] = max(maxw[u], maxw[f]);
minw[u] = min(minw[u], minw[f]);
return ancestor[u];
}
void tarjan(int u) {
vis[u] = true;
ancestor[u] = u;
for(int i = headE[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if(vis[v]) continue;
tarjan(v);
ancestor[v] = u;
}
for(int i = headQ[u]; ~i; i = Q[i].nxt) {
int v = Q[i].v;
if(!vis[v]) continue;
int lca = find(v);
addLCA(lca, i);
}
for(int i = headL[u]; ~i; i = L[i].nxt) {
int id = L[i].id;
if(id & 1) id ^= 1;
int u = Q[id].u, v = Q[id].v;
find(u); find(v); //there's one path to lca hasn't been updated
ans[id >> 1] = max(max(up[u], down[v]), maxw[v] - minw[u]);
}
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
while(scanf("%d", &n) == 1) {
for(int i = 1; i <= n; ++i) {
scanf("%d", minw + i);
maxw[i] = minw[i];
up[i] = down[i] = 0;
}
cnt = 0; memset(headE, -1, sizeof headE);
for(int i = 1; i < n; ++i) {
int u, v; scanf("%d%d", &u, &v);
addEdge(u, v);
}
scanf("%d", &q);
cnt = 0; memset(headQ, -1, sizeof headQ);
for(int i = 1; i <= q; ++i) {
int u, v; scanf("%d%d", &u, &v);
addQuery(u, v);
}
cnt = 0; memset(headL, -1, sizeof headL);
memset(vis, false, sizeof vis);
tarjan(1);
for(int i = 0; i < q; ++i)
printf("%d\n", ans[i]);
}
return 0;
}
也这个可以倍增搞
代码:
//
// Created by TaoSama on 2015-11-10
// Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 5e4 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
const int M = N << 1;
int n, q, w[N], dep[N], p[16][N];
int up[16][N], down[16][N], maxw[16][N], minw[16][N];
struct Edge {
int v, nxt;
} edge[M];
int head[N], cnt;
void addEdge(int u, int v) {
edge[cnt] = (Edge) {v, head[u]};
head[u] = cnt++;
}
void getMin(int& x, int y) {
x = min(x, y);
}
void getMax(int& x, int y) {
x = max(x, y);
}
void dfs(int u, int f, int d) {
dep[u] = d; p[0][u] = f;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if(v == f) continue;
getMax(up[0][v], w[u] - w[v]);
getMax(down[0][v], w[v] - w[u]);
getMin(minw[0][v], w[u]);
getMax(maxw[0][v], w[u]);
dfs(v, u, d + 1);
}
}
void build() {
dfs(1, -1, 0);
for(int i = 0; i + 1 < 16; ++i) {
for(int v = 1; v <= n; ++v) {
if(p[i][v] < 0) {
p[i + 1][v] = -1;
up[i + 1][v] = up[i][v];
down[i + 1][v] = down[i][v];
maxw[i + 1][v] = maxw[i][v];
minw[i + 1][v] = minw[i][v];
} else {
p[i + 1][v] = p[i][p[i][v]];
up[i + 1][v] = max(max(up[i][v], up[i][p[i][v]]),
maxw[i][p[i][v]] - minw[i][v]);
down[i + 1][v] = max(max(down[i][v], down[i][p[i][v]]),
maxw[i][v] - minw[i][p[i][v]]);
maxw[i + 1][v] = max(maxw[i][v], maxw[i][p[i][v]]);
minw[i + 1][v] = min(minw[i][v], minw[i][p[i][v]]);
}
}
}
}
int lca(int u, int v) {
if(dep[u] > dep[v]) swap(u, v);
for(int i = 0; i < 16; ++i)
if(dep[v] - dep[u] >> i & 1)
v = p[i][v];
if(u == v) return u;
for(int i = 16 - 1; ~i; --i) {
if(p[i][u] != p[i][v]) {
u = p[i][u];
v = p[i][v];
}
}
return p[0][u];
}
pair<int, int> getUp(int u, int to) {
pair<int, int> ret(0, INF);
for(int i = 0; i < 16; ++i) {
if(dep[u] - dep[to] >> i & 1) {
getMax(ret.first, max(up[i][u], maxw[i][u] - ret.second));
getMin(ret.second, minw[i][u]);
u = p[i][u];
}
}
return ret;
}
pair<int, int> getDown(int u, int to) {
pair<int, int> ret(0, 0);
for(int i = 0; i < 16; ++i) {
if(dep[u] - dep[to] >> i & 1) {
getMax(ret.first, max(down[i][u], ret.second - minw[i][u]));
getMax(ret.second, maxw[i][u]);
u = p[i][u];
}
}
return ret;
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
while(scanf("%d", &n) == 1) {
for(int i = 1; i <= n; ++i) {
scanf("%d", w + i);
maxw[0][i] = minw[0][i] = w[i];
up[0][i] = down[0][i] = 0;
}
cnt = 0; memset(head, -1, sizeof head);
for(int i = 1; i < n; ++i) {
int u, v; scanf("%d%d", &u, &v);
addEdge(u, v);
addEdge(v, u);
}
build();
scanf("%d", &q);
while(q--) {
int u, v; scanf("%d%d", &u, &v);
int _lca = lca(u, v);
// prln(_lca);
pair<int, int> l = getUp(u, _lca), r = getDown(v, _lca);
// printf("%d %d %d %d\n", l.first, r.first, l.second , r.second);
printf("%d\n", max(max(l.first, r.first), r.second - l.second));
}
}
return 0;
}