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 }

 

posted @ 2020-03-02 10:51  IAT14  阅读(265)  评论(0编辑  收藏  举报