题目链接 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;
}