luoguP3066 Running Away From the Barn G 滑动窗口 树上差分
给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于等于k的点有多少个。
所以我们边深搜边维护一个递归栈,然后不断在栈内滑动,保持窗口内边的权值和小于k。从而得出每个点会给多少个点的答案做贡献。然后使用树上差分维护。
1 #include <cstdio> 2 using namespace std; 3 const int MAXN = 210000; 4 typedef long long ll; 5 int head[MAXN],to[MAXN],nxt[MAXN],dep[MAXN],fa[MAXN],pot[MAXN],tot[MAXN]; 6 ll val[MAXN],sum[MAXN]; 7 int cnt,n; 8 ll k; 9 void add(int x,int y,ll v) 10 { 11 nxt[++cnt] = head[x]; 12 to[cnt] = y; 13 head[x] = cnt; 14 val[cnt] = v; 15 } 16 void change(int rt,int x,int y) 17 { 18 tot[rt]--; 19 tot[fa[rt]]--; 20 tot[x]++; 21 tot[y]++; 22 } 23 void dfs(int x,ll now,int hd) 24 { 25 pot[dep[x]] = x; 26 ll tnow = now; 27 int thd = hd; 28 change(pot[hd],pot[hd],pot[dep[x]]); 29 for (int i = head[x];i;i = nxt[i]) 30 { 31 dep[to[i]] = dep[x] + 1; 32 fa[to[i]] = x; 33 sum[dep[x]] = val[i]; 34 while (now + val[i] > k) 35 now -= sum[hd++]; 36 now += val[i]; 37 dfs(to[i],now,hd); 38 now = tnow; 39 hd = thd; 40 } 41 } 42 void calc(int x) 43 { 44 for (int i = head[x];i;i = nxt[i]) 45 { 46 calc(to[i]); 47 tot[x] += tot[to[i]]; 48 } 49 } 50 int main() 51 { 52 scanf("%d%lld",&n,&k); 53 int tx; 54 ll tl; 55 for (int i = 2;i <= n;i++) 56 { 57 scanf("%d%lld",&tx,&tl); 58 add(tx,i,tl); 59 } 60 dep[1] = 1; 61 dfs(1,0,1); 62 calc(1); 63 for (int i = 1;i <= n;i++) 64 printf("%d\n",tot[i]); 65 return 0; 66 }
心之所动 且就随缘去吧