Lost My Music 凸包+可持久化栈+倍增

来源:互联网 发布:windows已出现关键问题 编辑:程序博客网 时间:2024/06/05 07:52

题意

这里写图片描述
这里写图片描述

分析

du表示根到u的距离,如果我们把(cu,du)看做一个点的话,其实就是要求斜率的最大值。
考虑在dfs的时候维护一个凸包,那么每次就是要求凸包的切线。暴力弹栈会超时,所以我们可以用倍增找到弹栈点,然后把栈可持久化一下就好了。具体实现就是把栈写成一个链表的形式即可。
细节较多但代码十分简短。
由于dfs会爆栈,所以改用bfs是很棒棒的。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<cmath>#include<queue>using namespace std;const int N=500005;const double eps=1e-8;int n,c[N],d[N],last[N],r[N],l[N],bz[N][20],fa[N],cnt;struct edge{int to,next;}e[N];double ans[N];queue<int> que;int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void addedge(int u,int v){    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;}double get_k(int x,int y){    return (double)1.0*(c[x]-c[y])/(d[x]-d[y]);}void bfs(){    que.push(1);    while (!que.empty())    {        int x=que.front();que.pop();        int y=x;d[x]=d[fa[x]]+1;        l[x]=bz[x][0]=fa[x];        for (int i=1;i<=16;i++) bz[x][i]=bz[bz[x][i-1]][i-1];        for (int i=16;i>=0;i--)        {            int z=bz[y][i];            if (!l[z]) continue;            if (get_k(l[z],z)>get_k(z,x)) y=z;        }        y=l[y];l[x]=bz[x][0]=y;ans[x]=-get_k(x,y);        for (int i=1;i<=16;i++) bz[x][i]=bz[bz[x][i-1]][i-1];        for (int i=last[x];i;i=e[i].next) que.push(e[i].to);    }}int main(){    freopen("lost.in","r",stdin);freopen("lost.out","w",stdout);    n=read();    for (int i=1;i<=n;i++) c[i]=read();    for (int i=2;i<=n;i++) fa[i]=read(),addedge(fa[i],i);    bfs();    for (int i=2;i<=n;i++) if (fabs(ans[i])<eps) ans[i]=fabs(ans[i]);    for (int i=2;i<=n;i++) printf("%.10lf\n",ans[i]);    return 0;}