Codeforces 739B Alyona and a tree(树上路径倍增及差分)
题目链接 Alyona and a tree
比较考验我思维的一道好题。
首先,做一遍DFS预处理出$t[i][j]$和$d[i][j]$。$t[i][j]$表示从第$i$个节点到离他第$2^{j}$近的祖先,$d[i][j]$表示从$i$开始到$t[i][j]$的路径上的路径权值总和。
在第一次DFS的同时,对节点$x$进行定位(结果为$dist(x, y)<=a(y)$)的离$x$最远的$x$的某个祖先,然后进行$O(1)$的差分。
第一次DFS完成后,做第二次DFS统计答案(统计差分后的结果)
时间复杂度$O(NlogN)$
#include <bits/stdc++.h> using namespace std; #define REP(i, n) for(int i(0); i < (n); ++i) #define rep(i, a, b) for(int i(a); i <= (b); ++i) #define dec(i, a, b) for(int i(a); i >= (b); --i) #define LL long long #define sz(x) (int)x.size() const int N = 200000 + 10; const int A = 30 + 1; vector <int> v[N], c[N]; LL a[N], deep[N]; LL x, y; int n, cnt; LL t[N][A], d[N][A]; LL g[N], value[N]; LL s[N]; LL ans[N]; void dfs(int x, int fa){ if (g[x]){ t[x][0] = g[x]; d[x][0] = value[x]; for (int i = 0; t[t[x][i]][i]; ++i){ t[x][i + 1] = t[t[x][i]][i]; d[x][i + 1] = d[t[x][i]][i] + d[x][i]; } int now = x, noww = 0; bool flag = false; dec(i, 20, 0){ if (t[now][i] && d[now][i] + noww <= a[x]){ noww += d[now][i]; now = t[now][i]; flag = true; } } if (flag){ --s[g[now]]; ++s[g[x]]; } } REP(i, sz(v[x])){ int u = v[x][i]; deep[u] = deep[x] + 1; dfs(u, x); } } void dfs2(int x){ ans[x] += s[x]; REP(i, sz(v[x])){ dfs2(v[x][i]); ans[x] += ans[v[x][i]]; } } int main(){ scanf("%d", &n); rep(i, 1, n) scanf("%lld", a + i); rep(i, 2, n){ scanf("%lld%lld", &x, &y); g[i] = x; value[i] = y; v[x].push_back(i), c[x].push_back(y); } memset(s, 0, sizeof s); cnt = 0; deep[1] = 0; dfs(1, 0); memset(ans, 0, sizeof ans); dfs2(1); rep(i, 1, n - 1) printf("%lld ", ans[i]); printf("%lld\n", ans[n]); return 0; }