重金5块钱求大佬帮忙看一下这道题我哪里错了?
查看原帖
重金5块钱求大佬帮忙看一下这道题我哪里错了?
291976
quanjun楼主2022/5/6 10:05

我的思路和题解里面的思路是一样的,就是利用类似在线LCA的倍增思想求距离节点u的最远祖先,然后求树上差分。

参考的题解的链接:https://www.luogu.com.cn/blog/biubiuchuan1/cf739b-alyona-and-a-tree-ti-xie-bao-gao-di-yi-pian-ti-xie-post

下面是我的代码,请各位大佬帮忙看看哪里错了,我会发送 55 块钱红包作为感谢:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;

/**
a[i] 节点i的权值
w[i] 节点i连向其父节点的那条边的边权
f[i][j] 节点i的深度比它小2^j的祖先借点(不存在则为1)
cnt[i] 树上倍增所需的差分数组
dis[i] 节点i与根节点的距离
*/
int n, a[maxn], w[maxn], f[maxn][21], cnt[maxn];
long long dis[maxn];
vector<int> g[maxn];

/**
u 当前节点, p父节点, d当前节点距离根节点的路径长度
*/
void dfs1(int u, int p, long long d) {
    dis[u] = d;
    f[u][0] = p;
    for (auto v : g[u])
        dfs1(v, u, d + w[v]);
}

/**
用倍增思路求解节点u的距离他不超过a[u]的最远祖先节点编号
*/
int getid(int u) {
    long long d = dis[u] - a[u];
    for (int i = 20; i >= 0; i--) {
        int p = f[u][i];
        if (dis[p] >= d) u = p;
    }
    return u;
}

/**
树上差分,类似求前缀和
*/
void dfs2(int u) {
    for (auto v : g[u]) {
        dfs2(v);
        cnt[u] += cnt[v];
    }
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int v = 2; v <= n; v++) {
        int u;
        cin >> u >> w[v];
        g[u].push_back(v);
    }
    dfs1(1, 1, 0);
    for (int u = 1; u <= n; u++)
        for (int i = 1; i <= 20; i++)
            f[u][i] = f[ f[u][i-1] ][i-1];
    for (int u = 2; u <= n; u++) {
        int pp = getid(u);
        if (pp == u) continue;
        if (u != 1) cnt[f[u][0]]++;
        if (pp != 1) cnt[f[pp][0]]--;
    }
    dfs2(1);
    for (int i = 1; i <= n; i++) cout << cnt[i] << " ";
    return 0;
}
2022/5/6 10:05
加载中...