[模拟赛]最亲祖先

[模拟赛] 最亲祖先

思路:

考虑为链的情况,显然使用单调栈。在此基础上,树的做法便显而易见了。用链表实现栈,弹出元素时使用倍增。时间复杂度\(O(nlog_2n)\)

\[\mathfrak{Talk\ is\ cheap,show\ you\ the\ code.} \]

#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define Type template<typename T>
# define read read1<ll>()
Type T read1(){
    T t=0;
    char k;
    bool vis=0;
    do (k=getchar())=='-'&&(vis=1);while('0'>k||k>'9');
    while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
    return vis?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)   
ll a[500005];
int s,h[500005],sta[500005],la[500005][21];
vector<int>G[500005];
double ans[500005];
void dfs(int n,int w){
    la[s+1][0]=w;w=s+1;
    for(int i=0;i<20;++i)la[w][i+1]=la[la[w][i]][i];
    for(int x=20;~x;--x)
        if(la[la[w][x]][0]&&(a[la[w][x]]-a[n])*(h[la[w][x]]-h[la[la[w][x]][0]])>(a[la[la[w][x]][0]]-a[la[w][x]])*(h[n]-h[la[w][x]]))w=la[w][x];
    w=la[w][0];
    if(n!=1)ans[n]=1.0*(a[w]-a[n])/(h[n]-h[w]);
    la[n][0]=w;
    for(int i=0;i<20;++i)la[n][i+1]=la[la[n][i]][i];
    for(int i=0;i<G[n].size();++i)
        h[G[n][i]]=h[n]+1,dfs(G[n][i],n);
}
int main(){
    //fre("dearest");
    s=read;
    for(int i=1;i<=s;++i)a[i]=read;
    for(int i=2;i<=s;++i){
        int x=read;
        G[x].push_back(i);
    }
    dfs(1,0);
    for(int i=2;i<=s;++i)
        printf("%.9f\n",ans[i]);
    return 0;
}
posted @ 2020-11-08 15:38  ファイナル  阅读(75)  评论(0)    收藏  举报