题解 [牛客练习赛60E] 旗鼓相当的对手

旗鼓相当的对手

https://ac.nowcoder.com/acm/contest/4853/E

题目描述

给定一个 个点的树,树有点权。

如果 的最近公共祖先(LCA),并且 的树上距离等于 ,那么点 的答案就会加上

求所有点的答案。

正解

考虑暴力 dp,设 表示 的子树内离 的距离为 的点的个数,设 表示 的子树内离 的距离为 的点权和。

每次合并一颗子树,更新答案并且更新 dp 数组,时间复杂度

发现 dp 复杂度只跟深度有关,那么长链剖分后可以优化复杂度至

其实还有 dsu 的做法,每次暴力合并复杂度也没有问题,是 的。

这里给出长链剖分的代码 :

#include <bits/stdc++.h>
#define N 100005

using namespace std;

int n, k;
int o[N], d[N], a[N], totVec;
int fa[N], wson[N], dist[N];
int head[N], nex[N << 1], to[N << 1], ecnt;

long long ans[N];
vector<long long> f[N], g[N];


inline int read() {
    int x = 0; char ch = getchar();
    while(!isdigit(ch)) ch = getchar();
    while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    return x;
}
inline void addE(int u, int v) {
    to[++ecnt] = v;
    nex[ecnt] = head[u], head[u] = ecnt;
}

void preDfs(int u) {
    for(int i = head[u], v; i; i = nex[i]) {
        v = to[i];
        if(v == fa[u]) continue;
        fa[v] = u, preDfs(v);
        if(dist[wson[u]] < dist[v])
            wson[u] = v;
    }
    dist[u] = dist[wson[u]] + 1;
}

void dfs(int u, int top) {
    if(u == top) {
        o[u] = ++totVec;
        f[o[u]].resize(dist[u]);
        g[o[u]].resize(dist[u]);
    }
    if(wson[u]) {
        o[wson[u]] = o[u];
        d[wson[u]] = d[u] + 1;
        dfs(wson[u], top);
    }

    ++f[o[u]][d[u]];
    g[o[u]][d[u]] += a[u];
    for(int i = head[u], v; i; i = nex[i]) {
        v = to[i];
        if(v == fa[u] || v == wson[u]) continue;
        dfs(v, v);
        for(int j = 0; j < dist[v]; ++j)
            if(k - j - 1 > 0 && k - j - 1 + d[u] < dist[top]) {
                ans[u] += f[o[u]][k - j - 1 + d[u]] * g[o[v]][j];
                ans[u] += g[o[u]][k - j - 1 + d[u]] * f[o[v]][j];
            }
        for(int j = 0; j < dist[v]; ++j) {
            f[o[u]][j + 1 + d[u]] += f[o[v]][j];
            g[o[u]][j + 1 + d[u]] += g[o[v]][j];
        }
    }
}

int main() {
    n = read(), k = read();
    for(int i = 1; i <= n; ++i)
        a[i] = read();
    for(int i = 1, u, v; i < n; ++i) {
        u = read(), v = read();
        addE(u, v), addE(v, u);
    }

    preDfs(1);
    dfs(1, 1);

    for(int i = 1; i <= n; ++i)
        printf("%lld%c", ans[i], " \n"[i == n]);
    return 0;
}
全部评论
长链剖分不用指针怎么保证的复杂度O(n)啊 刚刚入门长剖 回来来补这个题 没太看懂QAQ
点赞 回复 分享
发布于 2020-04-08 13:16
dsu怎么写O(n*logn)啊
点赞 回复 分享
发布于 2020-04-03 03:21
orz lsk %%%
点赞 回复 分享
发布于 2020-03-28 07:42

相关推荐

不愿透露姓名的神秘牛友
07-15 17:46
暑期就挂了,秋招还有机会吗
大聪明777:研发提前批,14号刚开的,官网上面的配图上有写。提前批没过的话,秋招还可以投,不过前面的笔试/面试记录会被保留,供秋招参考
26届校招投递进展
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-16 14:00
机械打工仔:来挂自己了,经典巨婴从校园投入职场
点赞 评论 收藏
分享
评论
3
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务