1. 程式人生 > >GYM - 101147 J.Whistle's New Car

GYM - 101147 J.Whistle's New Car

i++ () 預處理 oid stl void opened 題意 bits

題意:

  給出一顆有點權和邊權的樹。求每一個點u的子樹中有多少點v,使得點v到點u的距離小於等於點v的權值。

題解:

  對於每一個點,倍增的預處理出他的祖宗節點及距離。根據預處理的結果求出每個點能到的最遠的祖宗節點。

  設點u能到的最遠祖宗節點為v。利用差分的思想在點tree[u]+1,點tree[v]-1。

  最後每個點的答案就是子樹的tree[]和。

技術分享圖片
#include <bits/stdc++.h> 
using namespace std;
typedef long long ll;
const int maxn = 5e5+10;
int t, n, u, v, tree[maxn], ans[maxn];
ll c, x[maxn];
struct node { ll val; int nod; }; node fa[32][maxn], tmp; vector<node> g[maxn]; void dfs(int u, int pre) { fa[0][u].nod = pre; int len = g[u].size(); for(int i = 0; i < len; i++) { int v = g[u][i].nod; if(v==pre) { fa[0][u].val = g[u][i].val;
continue; } dfs(v, u); } } void dfs_double(int u, int pre) { int len = g[u].size(); for(int i = 0; i < len; i++) { int v = g[u][i].nod; if(v==pre) continue; dfs_double(v, u); } tree[u]++; ll tv = x[u]; for(int k = 31; k >= 0; k--) {
if(fa[k][u].val <= tv) { tv -= fa[k][u].val; u = fa[k][u].nod; } } tree[u]--; } void solve(int u, int pre) { int len = g[u].size(); for(int i = 0; i < len; i++) { int v = g[u][i].nod; if(v==pre) continue; solve(v, u); } for(int i = 0; i < len; i++) { int v = g[u][i].nod; if(v==pre) continue; ans[u] += tree[v]+ans[v]; } } int main() { freopen("car.in","r",stdin); scanf("%d", &t); while(t--) { scanf("%d", &n); memset(tree, 0, sizeof(tree)); memset(ans, 0, sizeof(ans)); for(int i = 1; i <= n; i++) g[i].clear(); for(int i = 1; i <= n; i++) scanf("%lld", &x[i]); for(int i = 1; i < n; i++) { scanf("%d%d%lld", &u, &v, &tmp.val); tmp.nod = v; g[u].push_back(tmp); tmp.nod = u; g[v].push_back(tmp); } dfs(1, 1); for(int k = 0; k < 31; k++) { for(int v = 1; v <= n; v++) { fa[k+1][v].nod = fa[k][fa[k][v].nod].nod; fa[k+1][v].val = fa[k][v].val+fa[k][fa[k][v].nod].val; } } dfs_double(1, 0); solve(1, 0); for(int i = 1; i <= n; i++) { printf("%d", ans[i]); if(i==n) puts(""); else printf(" "); } } }
View Code

GYM - 101147 J.Whistle's New Car