USACO 2012 December Contest Gold, Running Away From the Barn
N頂点の木が与えられるので各点について、距離がL以下かつ部分木に含まれる点の個数を出力せよ
(N <= 200000)
各点について距離L以内でどこまで上に上がれるかわかればimos法するだけになるのでダブリングで処理
//include //------------------------------------------ #include <vector> #include <list> #include <map> #include <set> #include <deque> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <ctime> #include <queue> #include <climits> using namespace std; typedef long long ll; typedef pair<int, ll> P; //container util //------------------------------------------ #define pb push_back #define mp make_pair #define fi first #define se second //repetition //------------------------------------------ #define FOR(i,a,b) for(int i=(a);i<(b);++i) #define rep(i,n) FOR(i,0,n) #define foreach(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++) int n; ll l; ll d[200010]; vector<P> g[200010]; int par[200010][19]; int r[200010]; inline void build(int v, ll dep, int p){ par[v][0] = p; d[v] = dep; rep(i, g[v].size()) build(g[v][i].fi, dep + g[v][i].se, v); } int main(){ freopen("runaway.in", "r", stdin); freopen("runaway.out", "w", stdout); scanf("%d %lld", &n, &l); par[0][0] = -1; rep(i, n - 1){ int p; ll len; scanf("%d %lld", &p, &len); --p; g[p].pb(mp(i + 1, len)); } build(0, 0, -1); rep(i, 18){ rep(j, n){ if(par[j][i] < 0) par[j][i + 1] = -1; else par[j][i + 1] = par[par[j][i]][i]; } } rep(i, n){ int v = i; ll cur = 0; ++r[v]; for(int j = 18; j >= 0; --j){ if(par[v][j] == -1) continue; if(cur + d[v] - d[par[v][j]] <= l){ cur += d[v] - d[par[v][j]]; v = par[v][j]; } } if(par[v][0] != -1) --r[par[v][0]]; } for(int i = n - 1; i >= 0; --i) if(par[i][0] != -1) r[par[i][0]] += r[i]; rep(i, n) printf("%d\n", r[i]); return 0; }