ZOJ 3937 More Health Points (2016 浙江省赛 B题,可持久维护凸壳)
题目链接 2016 ZJCPC Problem B
题意 CF 660F的树上版本。
其他做的方法都差不多,关键是把凸壳放到树上。
每次确定扔掉几个元素的时候直接$O(1)$修改(先不清楚这个位置之后的元素因为之后还要恢复),然后$O(1)$恢复,通过这个来实现可持久。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define MP make_pair #define fi first #define se second typedef long long LL; const int N = 1e5 + 10; int T; int n; int r; int deep[N], q[N]; LL a[N], c[N], s[N]; LL ans; vector <int> v[N]; inline LL y(int x){ return c[x] - 1ll * deep[x] * s[x]; } inline long double g(int j, int k){ double dy = 1.00 * y(j) - 1.00 * y(k); double dx = 1.00 * deep[j] - 1.00 * deep[k]; return dy / dx; } inline LL calc(int x, int y){ return c[x] - c[y] - 1ll * deep[y] * (s[x] - s[y]); } void pre(int x, int fa, int dep){ deep[x] = dep; s[x] = s[fa] + a[x]; c[x] = c[fa] + 1ll * dep * a[x]; for (auto u : v[x]){ pre(u, x, dep + 1); } } inline int pos(LL x, int tail){ x = -x; int l = 1, r = tail - 1, ret = 0; while (l <= r){ int mid = (l + r) >> 1; if (g(q[mid], q[mid - 1]) < x) l = (ret = mid) + 1; else r = mid - 1; } return q[ret]; } inline int gettail(int x, int tail){ int l = 2, r = tail, ret = 0; if (g(x, q[1]) < g(q[1], q[0])) return 1; while (l <= r){ int mid = (l + r) >> 1; if (g(x, q[mid - 1]) >= g(q[mid - 1], q[mid - 2])) l = (ret = mid) + 1; else r = mid - 1; } return ret; } void dfs(int x, int tail){ int y = pos(s[x], tail); ans = max(ans, calc(x, y)); int cnt, t, re, la; if (tail <= 1 || g(x, q[tail - 1]) >= g(q[tail - 1], q[tail - 2])){ re = tail; la = q[tail]; q[tail] = x; tail++; cnt = tail; } else{ t = gettail(x, tail); //get the position re = t; la = q[t]; q[t] = x; cnt = t + 1; } //replace for (auto u : v[x]) dfs(u, cnt); //continue solving q[re] = la; //undo } int main(){ scanf("%d", &T); while (T--){ scanf("%d", &n); rep(i, 0, n + 1) v[i].clear(); rep(i, 1, n) scanf("%lld", a + i); rep(i, 2, n){ int x; scanf("%d", &x); v[x].push_back(i); } pre(1, 0, 1); rep(i, 0, n + 1) q[i] = 0; r = 0; q[r++] = 0; ans = 0; dfs(1, r); printf("%lld\n", ans); } return 0; }