【NOIP2017提高A组模拟10.8】Lost My Music

Description:

这里写图片描述
1<=n<= 5105

题解:

由于本人太弱,不会什么斜率优化,所以只能这样做了:
设答案为Ans。

cvcudis(u,v)<=ans

cvcudepudepv<=ans

cvcu<=ans(depudepv)

cv+ansdepv<=cu+ansdepu

把dep看作斜率,c看作一次函数中y=kx+b的b.

ansu 其实就是u的直线和v的直线交点(v是u的祖先)的横坐标的最大值。

于是可以维护交点递增的一个单调栈。

可是这是树上的,如果暴力退栈和还原栈是会T的。

树上也就树上,可以搞个可持久化栈。

至于弹栈可以用倍增弹,因为这个满足单调性。

Code:

#include
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
using namespace std;

const int N = 500005;

int n, x, y, c[N];
int tot, final[N], to[N], next[N];
int dep[N];
int z[N];
double ans[N];
int fa[N], f[19][N], g, d[N], gg[N];

double ji(int x, int y, int u, int v) {
    return (double)(y - v) / (double)(u - x);
}

void Bei(int &g, int x) {
    if(g > 1) {
        fd(i, 18, 0) if(f[i][g] > 1) {
            int y = f[i][g];
            if(ji(dep[y], c[y], dep[fa[y]], c[fa[y]]) <= ji(dep[y], c[y], dep[x], c[x]))
                g = y;
        }
        if(ji(dep[g], c[g], dep[fa[g]], c[fa[g]]) <= ji(dep[g], c[g], dep[x], c[x]))
            g = fa[g];
    }
    fa[x] = f[0][x] = g;
    fo(i, 1, 18) f[i][x] = f[i - 1][f[i - 1][x]];
    g = x;
}

void dg(int x) {
    int z = g;
    g = z;
}

int main() {
    freopen("lost.in", "r", stdin);
    freopen("lost.out", "w", stdout);
    scanf("%d", &n);
    fo(i, 1, n) scanf("%d", &c[i]);
    fo(i, 2, n) {
        scanf("%d", &x);
        next[++ tot] = final[x], to[tot] = i, final[x] = tot;
    }
    dep[1] = 1; d[1] = 1;
    for(int st = 1, en = 1; st <= en; st ++) {
        int x = d[st], g = gg[x];
        Bei(g, x);
        if(x > 1) ans[x] = ji(dep[g], c[g], dep[fa[g]], c[fa[g]]);
        for(int i = final[x]; i; i = next[i])
            dep[to[i]] = dep[x] + 1, d[++ en] = to[i], gg[to[i]] = g;
    }
    fo(i, 2, n) printf("%.10lf\n", ans[i]);
}

你可能感兴趣的:(动态规划,单调队列,&&,单调栈,分治,斜率优化)