阔力梯的树

阔力梯的树

题面

点击查看

题解

树上问题, 树链剖分, lca变成线性, 点分治, 点分树, dsu on tree

这道题是 dsu on tree, 还是要用时间戳这个好东西, 可以维护子树

然后就是加子树入编号影响的问题, 用set维护就好了

int n, m, _, k, cas;
VI h[N];
int dfn[N], low[N], df, son[N], sz[N], rk[N];
ll ans[N], sum;
set<int> st;

void dfs(int x) {
    rk[dfn[x] = ++df] = x, sz[x] = 1;
    for (auto &y : h[x]) {
        dfs(y); sz[x] += sz[y];
        if (!son[x] || sz[y] > sz[son[x]]) son[x] = y;
    }
    low[x] = df;
}

void add(ll x) {
    if (st.empty()) { st.insert(x); return; }
    auto it = st.lower_bound(x);
    if (it == st.begin()) sum += sqr(x - *it), st.insert(x);
    else if (it == st.end()) --it, sum += sqr(x - *it), st.insert(x);
    else {
        ll cur = *it; sum += sqr(x - cur); --it;
        sum += sqr(x - *it) - sqr(*it - cur); st.insert(x); 
    }
}

void dsu(int x, bool f) {
    for (auto &y : h[x]) if (y ^ son[x]) dsu(y, 0);
    if (son[x]) dsu(son[x], 1);
    for (auto &y : h[x]) if (y ^ son[x]) rep (j, dfn[y], low[y]) add(rk[j]);
    add(x); ans[x] = sum;
    if (!f) clear(st), sum = 0;
}

int main() {
    IOS; cin >> n;
    rep (i, 2, n) cin >> m, h[m].pb(i);
    dfs(1); dsu(1, 0);
    rep (i, 1, n) cout << ans[i] << '\n';
    return 0;
}
posted @ 2021-03-15 19:25  洛绫璃  阅读(76)  评论(0编辑  收藏  举报