JZOJ 5403. 【NOIP2017提高A组模拟10.8】Lost My Music
可以这很noip模拟
可以化简一下求得东西:$\frac{c_v-c_u}{dis(u,v)}=\frac{c_v-c_u}{dep_u-dep_v}=-\frac{c_u-c_v}{dep_u-dep_v}$
很显然的斜率表达式……那么如果把点看作为$(dep_u,c_u)$,那么答案一定在凸包上……
准确的说是下凸壳上,因为$dep$是单调递增的
然而这个在树上的查询凸包,类似于维护返祖链上的凸包,然而这个凸包是需要支持回滚的,复杂度十分不对
于是可以想到可持久化栈,套上倍增后就相当于是一个序列上的单调栈了,类似于维护凸包一样
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 5e5 + 10; 4 5 vector<int> G[N]; 6 7 int c[N], ans[N], dep[N], fa[N][21], n, from[N]; 8 9 double calc(int u, int v) { // dep[u] > dep[v] 10 return 1.0 * (c[v] - c[u]) / (dep[u] - dep[v]); 11 } 12 13 int main() { 14 freopen("lost.in", "r", stdin); 15 freopen("lost.out", "w", stdout); 16 scanf("%d", &n); 17 for(int i = 1 ; i <= n ; ++ i) scanf("%d", &c[i]); 18 for(int i = 2, fa ; i <= n ; ++ i) scanf("%d", &fa), G[fa].push_back(i); 19 queue<int> q; 20 q.push(1), dep[1] = 1; 21 while(q.size()) { 22 int u = q.front(); q.pop(); 23 for(int v: G[u]) from[v] = u, dep[v] = dep[u] + 1, q.push(v); 24 if(u == 1) continue; 25 int x = from[u]; 26 for(int i = 20 ; ~ i ; -- i) { 27 if(fa[x][i] <= 1) continue; 28 if(calc(u, fa[x][i]) >= calc(u, fa[fa[x][i]][0])) { 29 x = fa[fa[x][i]][0]; 30 } 31 } 32 if(x > 1 && calc(u, x) >= calc(u, fa[x][0])) 33 x = fa[x][0]; 34 ans[u] = fa[u][0] = x; 35 for(int j = 1 ; j <= 20 ; ++ j) fa[u][j] = fa[fa[u][j - 1]][j - 1]; 36 } 37 for(int i = 2 ; i <= n ; ++ i) printf("%lf\n", calc(i, ans[i])); 38 }