Codeforces 739B Alyona and a tree (树上路径倍增及差分)
题目链接 Alyona and a tree
弄了好几个小时终于Accepted了,之后发现这个题是Div1的。
比较考验我思维的一道好题。
首先,做一遍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(NlgN)
代码送上。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define REP(i,n) for(int i(0); i < (n); ++i) 6 #define rep(i,a,b) for(int i(a); i <= (b); ++i) 7 #define dec(i,a,b) for(int i(a); i >= (b); --i) 8 #define for_edge(i,x) for(int i = H[x]; i; i = X[i]) 9 10 #define LL long long 11 #define ULL unsigned long long 12 #define MP make_pair 13 #define PB push_back 14 #define FI first 15 #define SE second 16 #define INF 1 << 30 17 #define sz(x) (int)x.size() 18 19 const int N = 200000 + 10; 20 const int M = 10000 + 10; 21 const int Q = 1000 + 10; 22 const int A = 30 + 1; 23 24 25 vector <int> v[N], c[N]; 26 LL a[N], deep[N]; 27 LL x, y; 28 int n, cnt; 29 LL t[N][A], d[N][A]; 30 LL g[N], value[N]; 31 LL s[N]; 32 LL ans[N]; 33 34 void dfs(int x, int fa){ 35 if (g[x]){ 36 t[x][0] = g[x]; 37 d[x][0] = value[x]; 38 for (int i = 0; t[t[x][i]][i]; ++i){ 39 t[x][i + 1] = t[t[x][i]][i]; 40 d[x][i + 1] = d[t[x][i]][i] + d[x][i]; 41 } 42 int now = x, noww = 0; 43 bool flag = false; 44 dec(i, 20, 0){ 45 if (t[now][i] && d[now][i] + noww <= a[x]){ 46 noww += d[now][i]; 47 now = t[now][i]; 48 flag = true; 49 } 50 } 51 if (flag){ 52 --s[g[now]]; ++s[g[x]]; 53 } 54 } 55 56 REP(i, sz(v[x])){ 57 int u = v[x][i]; 58 deep[u] = deep[x] + 1; 59 dfs(u, x); 60 } 61 } 62 63 void dfs2(int x){ 64 ans[x] += s[x]; 65 REP(i, sz(v[x])){ 66 dfs2(v[x][i]); 67 ans[x] += ans[v[x][i]]; 68 } 69 } 70 71 int main(){ 72 73 scanf("%d", &n); 74 rep(i, 1, n) scanf("%lld", a + i); 75 rep(i, 2, n){ 76 scanf("%lld%lld", &x, &y); g[i] = x; value[i] = y; 77 v[x].PB(i), c[x].PB(y); 78 } 79 80 memset(s, 0, sizeof s); 81 cnt = 0; 82 deep[1] = 0; 83 dfs(1, 0); 84 memset(ans, 0, sizeof ans); 85 dfs2(1); 86 rep(i, 1, n - 1) printf("%lld ", ans[i]); 87 printf("%lld\n", ans[n]); 88 89 return 0; 90 91 }