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 }
JZOJ 5403. 【NOIP2017提高A组模拟10.8】Lost My Music
posted @ 2018-08-09 20:48  KingSann  阅读(325)  评论(0编辑  收藏  举报