Description
n<=5∗105,ci<=109
凸壳
将dis(u,v)写成dep[u]-dep[v],这就是个斜率的形式
手动脑补一下可以发现我们只需要用单调栈维护根到当前点u的一个凸壳,即可算出答案
暴力弹栈,暴力加入复杂度是O(n^2)的,我们需要优化
倍增
记录每个点在凸壳上的前一个点,于是我们不需要暴力弹栈,可以倍增二分判断
成功将复杂度优化为O(nlogn)
貌似呢这种姿势,其实就是可持久化栈
Code
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,b,a) for(int i=b;i>=a;i--)
#define efo(i,v,u) for(int i=last[v],u=to[i];i;i=next[i],u=to[i])
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
typedef double db;
char ch;
void read(int &n)
{
n=0;int p=1;
for(ch=getchar();ch<'0' || ch>'9';ch=getchar())
if(ch=='-') p=-1;
for(;'0'<=ch && ch<='9';ch=getchar()) n=n*10+ch-'0';
n*=p;
}
const int N=5e5+5;
int n,tot,to[N+N],next[N+N],last[N],c[N],d[N],fa[N];
void link(int u,int v){to[++tot]=v,next[tot]=last[u],last[u]=tot;}
int pre[N][22];
db ans[N];
queue<int> q;
bool bz[N];
db xl(int i,int j)
{
return 1.0*(c[i]-c[j])/(d[j]-d[i]);
}
void bfs()
{
q.push(1);
while(!q.empty())
{
int v=q.front();q.pop();
d[v]=d[fa[v]]+1;
int x=fa[v];
fd(j,20,0)
if(pre[pre[x][j]][0] && xl(pre[pre[x][j]][0],pre[x][j])<xl(pre[x][j],v)) x=pre[pre[x][j]][0];
if(pre[x][0] && xl(pre[x][0],x)<xl(x,v)) x=pre[x][0];
pre[v][0]=x;
fo(j,1,20) pre[v][j]=pre[pre[v][j-1]][j-1];
ans[v]=xl(pre[v][0],v);
efo(i,v,u) q.push(u);
}
}
int main()
{
freopen("lost.in","r",stdin);
freopen("lost.out","w",stdout);
read(n);
fo(i,1,n) read(c[i]);
fo(i,2,n) read(fa[i]),link(fa[i],i);
bfs();
fo(i,2,n) printf("%.10lf\n",ans[i]);
return 0;
}