#Lost My Music 凸包+链表倍增优化 <凉宫春日的忧郁>
之前学斜率优化的锅,凸包没学会,当时是不等式搞过去的,考试时妄想推出和u无关,只和祖先有关的不等式,失败。。。
先看式子(c[fa]-c[son])/(dep[son]-dep[fa]),看起来很别扭,尝试加负号,就变成了斜率(我们以dep为x轴,dep为y轴建坐标系),要求斜率最大,为下凸包,
这是模拟一个点尝试进栈,两条橙线都不能维护成凸包,要出栈,绿线刚好可以,连绿线前的点也可以,不过并没有这条绿线优
kx地开栈?不太妙,如果是序列问题那是没问题,但树上问题,没下到一个子节点就会失去此节点应有信息,进而影响到其他子节点,所以考虑用链表,然而不太像前向星那种nt的链表,开个数组记录此点在栈中的上一个点是谁就可以了(可以说是pre)。
然后是T80的好成绩,考虑优化,这玩意很像一个fat数组,我们一个个找一定很慢的,要优化成跳一大段,想到树上倍增嘛,我们可以像树上倍增祖先一样,倍增此点多少辈pre
keycode:
sd[u]=sd[fa]+1;
lian[u][0]=fa;
int a,b;
for(reg int j=lim;j>=0;--j)
while(1){
a=lian[lian[u][0]][j];
if(!a)break;
b=lian[a][0];
if(!b)break;
if(cal(a,b)<cal(a,u))break;
lian[u][0]=b;
}
//cout<<u<<" "<<lian[u][0]<<endl;
while(1){
a=lian[u][0];
if(!a)break;
b=lian[a][0];
if(!b)break;
if(cal(a,b)<cal(a,u))break;
lian[u][0]=b;
}
zui[u]=-1.0*cal(lian[u][0],u);
for(reg int j=1;j<=lim;++j)
lian[u][j]=lian[lian[u][j-1]][j-1];
1 #include<cstdio>
2 #include<iostream>
3 #include<cmath>
4 #define reg register
5 using namespace std;
6 const int MAXN=500010;
7 int n;
8 double c[MAXN],sd[MAXN];
9 struct rr{
10 int nt,to;
11 }bl[MAXN];int hd[MAXN],itot;
12 void add(int x,int y){
13 bl[++itot].to=y;
14 bl[itot].nt=hd[x];
15 hd[x]=itot;
16 }
17 inline double cal(int s,int f){return (c[s]-c[f])/(sd[s]-sd[f]); }
18 int lian[MAXN][25];
19 double zui[MAXN];
20 int lim;
21 void dfs(int u,int fa){
22 sd[u]=sd[fa]+1;
23 lian[u][0]=fa;
24 int a,b;
25 for(reg int j=lim;j>=0;--j)
26 while(1){
27 a=lian[lian[u][0]][j];
28 if(!a)break;
29 b=lian[a][0];
30 if(!b)break;
31 if(cal(a,b)<cal(a,u))break;
32 lian[u][0]=b;
33 }
34 //cout<<u<<" "<<lian[u][0]<<endl;
35 while(1){
36 a=lian[u][0];
37 if(!a)break;
38 b=lian[a][0];
39 if(!b)break;
40 if(cal(a,b)<cal(a,u))break;
41 lian[u][0]=b;
42 }
43 zui[u]=-1.0*cal(lian[u][0],u);
44 for(reg int j=1;j<=lim;++j)
45 lian[u][j]=lian[lian[u][j-1]][j-1];
46 for(reg int i=hd[u];i;i=bl[i].nt)
47 dfs(bl[i].to,u);
48 }
49 int main(){
50 //freopen("da.in","r",stdin);
51 //freopen("hh.out","w",stdout);
52 scanf("%d",&n);
53 lim=log2(n)+1;
54 for(reg int i=1;i<=n;++i)scanf("%lf",&c[i]);
55 for(reg int i=2,a;i<=n;++i)scanf("%d",&a),add(a,i);
56 dfs(1,0);
57 for(reg int i=2;i<=n;++i)printf("%.6lf\n",zui[i]);
58 }