【CF739B】Alyona and a tree(树上差分,二分,树形DP)

题意:给出一棵有根树,树上每个点、每条边都有一个权值。

现在给出“控制”的定义:对一个点u,设点v在其子树上,且dis(u,v)≤av,则称u控制v。

要求求出每个点控制了多少个点

n (1?≤?n?≤?2·105).  (1?≤?ai?≤?109) 1?≤?pi?≤?n, 1?≤?wi?≤?109)

思路:在学校CF有时上不去不知道为什么

对于确定的点i,计算它对哪些点有贡献

dis[i]-dis[u]<=a[i]

dis[u]<=a[i]-dis[i]满足二分性

倍增枚举深度最小的i能给它贡献的点j

树上差分部分就是 inc(fa[i]) dec(fa[j])

最后统计出来的答案就是它子树里的和

注意INT64

 1 var f:array[0..210000,0..19]of longint;
 2     head,vet,next,len,flag,a:array[0..410000]of longint;
 3     dp,dep,dis:array[0..410000]of int64;
 4     n,tot,i,x,y,l,r,mid,last,j:longint;
 5
 6 procedure add(a,b,c:longint);
 7 begin
 8  inc(tot);
 9  next[tot]:=head[a];
10  vet[tot]:=b;
11  len[tot]:=c;
12  head[a]:=tot;
13 end;
14
15 procedure dfs(u:longint);
16 var e,v,i:longint;
17 begin
18  flag[u]:=1;
19  for i:=1 to 19 do
20  begin
21   if dep[u]<(1<<i) then break;
22   f[u,i]:=f[f[u,i-1],i-1];
23  end;
24  e:=head[u];
25  while e<>0 do
26  begin
27   v:=vet[e];
28   if flag[v]=0 then
29   begin
30    dep[v]:=dep[u]+1;
31    dis[v]:=dis[u]+len[e];
32    f[v,0]:=u;
33    dfs(v);
34   end;
35   e:=next[e];
36  end;
37 end;
38
39 procedure dfs2(u:longint);
40 var e,v:longint;
41 begin
42  flag[u]:=1;
43  e:=head[u];
44  while e<>0 do
45  begin
46   v:=vet[e];
47   if flag[v]=0 then
48   begin
49    dfs2(v);
50    dp[u]:=dp[u]+dp[v];
51   end;
52   e:=next[e];
53  end;
54 end;
55
56 function clac(x,y:longint):longint;
57 var i:longint;
58 begin
59  for i:=0 to 19 do
60   if y and (1<<i)>0 then x:=f[x,i];
61  exit(x);
62 end;
63
64 begin
65  //assign(input,‘cf739B.in‘); reset(input);
66  //assign(output,‘cf739B.out‘); rewrite(output);
67  readln(n);
68  for i:=1 to n do read(a[i]);
69  for i:=2 to n do
70  begin
71   readln(x,y);
72   add(i,x,y);
73   add(x,i,y);
74  end;
75  dfs(1);
76  fillchar(flag,sizeof(flag),0);
77  for i:=1 to n do
78  begin
79   l:=1; r:=dep[i]; last:=i;
80   while l<=r do
81   begin
82    mid:=(l+r)>>1;
83    j:=clac(i,mid);
84    if dis[i]-dis[j]<=a[i] then begin last:=j; l:=mid+1; end
85     else r:=mid-1;
86   end;
87   dec(dp[f[last,0]]);
88   inc(dp[f[i,0]]);
89  end;
90
91  dfs2(1);
92  for i:=1 to n-1 do write(dp[i],‘ ‘);
93  write(dp[n]);
94  //close(input);
95  //close(output);
96 end.
时间: 2024-11-05 06:06:05

【CF739B】Alyona and a tree(树上差分,二分,树形DP)的相关文章

CF739B Alyona and a tree 树上差分

题目描述 \(Alyona有一棵有 n个节点的树.这棵树的根节点是 1.在每个节点里,Alyona写了一个正整数,在节点 i 她写了正整数a_i .另外,她在这棵树上的每条边上写了一个正整数(不同边上可能有不同的数). 让我们定义 dist(v,u) 作为从 v 到 u 的简单路径上的边权和. 当且仅当 u 在 v 的子树中并且 dist(v,u)<=a_u,顶点 v 控制顶点 u(v!=u) .Alyona想在某些顶点定居.为了做到这件事,她想知道在每个节点 v 能控制几个节点.\) 对于\(

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统计答案(统

【BZOJ-4326】运输计划 树链剖分 + 树上差分 + 二分

4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 703  Solved: 461[Submit][Status][Discuss] Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui

NOIp2015 运输计划 [LCA] [树上差分] [二分答案]

我太懒了 吃掉了题面 题解 & 吐槽 一道很好的树上差分练习题. 不加fread勉强a过bzoj和luogu的数据,加了fread才能在uoj里卡过去. 可以发现,答案则是运输计划里花费的最大值,最大值最小,便是二分答案的标志. 那么该怎么check呢... 我们得找出所有超过限制的计划,这个过程可以在LCA倍增的过程中预处理出来. 然后再找出一些被这些计划都覆盖的边,找到最大的那条边,如果最大的计划花费减去最大的那条边小于x,那么x就是可行的. 但是该怎么找到那些被计划都覆盖的边呢... 我们

HDU 5293 TREE CHAIN PROBLEM LCT+树形DP

题解链接 代码链接 链接 Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 35    Accepted Submission(s): 8 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1

Codeforces 627D Preorder Test(二分+树形DP)

题意:给出一棵无根树,每个节点有一个权值,现在要让dfs序的前k个结点的最小值最大,求出这个值. 考虑二分答案,把>=答案的点标记为1,<答案的点标记为0,现在的任务时使得dfs序的前k个节点都为1. 考虑树形DP. 用dp[u]表示从节点u开始在子树中进行dfs最多可以经过多少个为1的结点,显然,若某一个子树中节点全为1,那么这个可以加到dp[u]中,此外还可以在不全为1的子树中挑选一个加到dp[u]上. 那么答案就是从标记为1的节点当做根,选两颗不完全子树和所有的完全子树(包括从父亲向上的

HDU 3586 Information Disturbing(二分+树形dp)

http://acm.split.hdu.edu.cn/showproblem.php?pid=3586 题意: 给定一个带权无向树,要切断所有叶子节点和1号节点(总根)的联系,每次切断边的费用不能超过上限limit,问在保证总费用<=m下的最小的limit. 思路: 对于上限limit我们可以二分查找.然后就是树形dp,看代码就可以理解的. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring>

CF739B Alyona and a tree

倍增+差分 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=2e5+10; #define int long long int n,a[N],f[N][21],ans[N],dis[N]; int Next[2*N],head[N],go[N*2],w[N*2],tot; inline void

Noip2015 运输计划 树上差分 二分答案

Code: #include<cstring> #include<cstdio> #include<algorithm> #include<string> using namespace std; void setIO(string a){freopen((a+".in").c_str(),"r",stdin);} #define maxn 300090 #define logn 20 int head[maxn],t

【BZOJ2525】[Poi2011]Dynamite 二分+树形DP

[BZOJ2525][Poi2011]Dynamite Description Byteotian Cave的结构是一棵N个节点的树,其中某些点上面已经安置了炸.药,现在需要点燃M个点上的引线引爆所有的炸.药. 某个点上的引线被点燃后的1单位时间内,在树上和它相邻的点的引线会被点燃.如果一个有炸.药的点的引信被点燃,那么这个点上的炸.药会爆炸. 求引爆所有炸.药的最短时间. 输入: 第一行是两个整数N,M.(1<=m<=n<=300000) 接下来一行有N个整数Di,第I个数为1表示该点