Description:
1<=n<=
5∗105
题解:
由于本人太弱,不会什么斜率优化,所以只能这样做了:
设答案为Ans。
cv−cudis(u,v)<=ans
cv−cudepu−depv<=ans
cv−cu<=ans∗(depu−depv)
cv+ans∗depv<=cu+ans∗depu
把dep看作斜率,c看作一次函数中y=kx+b的b.
ansu 其实就是u的直线和v的直线交点(v是u的祖先)的横坐标的最大值。
于是可以维护交点递增的一个单调栈。
可是这是树上的,如果暴力退栈和还原栈是会T的。
树上也就树上,可以搞个可持久化栈。
至于弹栈可以用倍增弹,因为这个满足单调性。
Code:
#include<cstdio>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
using namespace std;
const int N = 500005;
int n, x, y, c[N];
int tot, final[N], to[N], next[N];
int dep[N];
int z[N];
double ans[N];
int fa[N], f[19][N], g, d[N], gg[N];
double ji(int x, int y, int u, int v) {
return (double)(y - v) / (double)(u - x);
}
void Bei(int &g, int x) {
if(g > 1) {
fd(i, 18, 0) if(f[i][g] > 1) {
int y = f[i][g];
if(ji(dep[y], c[y], dep[fa[y]], c[fa[y]]) <= ji(dep[y], c[y], dep[x], c[x]))
g = y;
}
if(ji(dep[g], c[g], dep[fa[g]], c[fa[g]]) <= ji(dep[g], c[g], dep[x], c[x]))
g = fa[g];
}
fa[x] = f[0][x] = g;
fo(i, 1, 18) f[i][x] = f[i - 1][f[i - 1][x]];
g = x;
}
void dg(int x) {
int z = g;
g = z;
}
int main() {
freopen("lost.in", "r", stdin);
freopen("lost.out", "w", stdout);
scanf("%d", &n);
fo(i, 1, n) scanf("%d", &c[i]);
fo(i, 2, n) {
scanf("%d", &x);
next[++ tot] = final[x], to[tot] = i, final[x] = tot;
}
dep[1] = 1; d[1] = 1;
for(int st = 1, en = 1; st <= en; st ++) {
int x = d[st], g = gg[x];
Bei(g, x);
if(x > 1) ans[x] = ji(dep[g], c[g], dep[fa[g]], c[fa[g]]);
for(int i = final[x]; i; i = next[i])
dep[to[i]] = dep[x] + 1, d[++ en] = to[i], gg[to[i]] = g;
}
fo(i, 2, n) printf("%.10lf\n", ans[i]);
}