题目描述

给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于等于l的点有多少个。

输入格式

Line 1: 2 integers, N and L (1 <= N <= 200,000, 1 <= L <= 10^18)

Lines 2..N: The ith line contains two integers p_i and l_i. p_i (1 <= p_i < i) is the first pasture on the shortest path between pasture i and the barn, and l_i (1 <= l_i <= 10^12) is the length of that path.

输出格式

Lines 1..N: One number per line, the number on line i is the number pastures that can be reached from pasture i by taking roads that lead strictly farther away from the barn (pasture 1) whose total length does not exceed L.


这道题有很多高级的做法,但是我都不会

我们分析题目可以得出这样一条结论——对于当前节点u,u的子树中与u的距离大于l的点与u的所有祖先的距离都大于l(u也是自己的祖先)。所以不难想到我们对于每个节点u,我们计算出u的第一个与它距离大于l的祖先anc,那么对于这个祖先,它的答案就要减去size(u)。size表示子树的节点数,初始化每个点的答案为子树的节点数。然后结合之前得到的性质,我们可以用树上前缀和的思想,把这个减去的size(u)累加到anc的祖先中去。

但是你会发现,直接算是有问题的。

首先对于u,它对anc的答案做了值为-size(u)的贡献,并且我们要将这个贡献累加到anc的祖先中去。然后我们发现,对于u的祖先,比如u的父亲fa(u),第一个与fa(u)距离大于l的祖先也必定是anc的祖先,但我们将-size(fa(u))加到了这个祖先中,也就是说这个祖先的答案累加了两次-size(u),答案显然是错的。如何避免呢?很简单,我们将size(fa(u))减去size(u)即可。那么问题就解决了。

对于求第一个距离大于l的祖先,我们可以用倍增来做,那么总的时间复杂度就是O(NlogN)。

*由于size(fa(u))减去的是size(u)原本的大小,而此时size(u)可能已经被u的子节点减去了一些,所以我们要再开一个size数组来记录原本的size。

*不开long long见祖宗

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define maxn 200001
using namespace std; struct edge{
int to,next; long long dis;
edge(){}
edge(const int &_to,const long long &_dis,const int &_next){ to=_to,dis=_dis,next=_next; }
}e[maxn<<1];
int head[maxn],k; int fa[maxn][20],size[maxn],size2[maxn],sum[maxn],maxdep;
int n;
long long m,dis[maxn][20]; inline long long read(){
register long long x(0),f(1); register char c(getchar());
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
inline void add(const int &u,const int &v,const long long &w){ e[k]=edge(v,w,head[u]),head[u]=k++; } void dfs(int u){
size[u]=1;
for(register int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==fa[u][0]) continue;
fa[v][0]=u,dis[v][0]=e[i].dis;
for(register int j=1;j<=maxdep;j++) fa[v][j]=fa[fa[v][j-1]][j-1],dis[v][j]=dis[v][j-1]+dis[fa[v][j-1]][j-1];
dfs(v),size[u]+=size[v];
}
} void dfs_getsum(int u){
for(register int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==fa[u][0]) continue;
dfs_getsum(v);
long long len=0; int tmp=size[v],tmp2=size2[v];
for(register int j=maxdep;j>=0;j--) if(len+dis[v][j]<=m&&fa[v][j]) len+=dis[v][j],v=fa[v][j];
if(len+dis[v][0]>m&&fa[v][0]) sum[fa[v][0]]+=tmp,size[u]-=tmp2;
}
} void dfs_getans(int u){
for(register int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==fa[u][0]) continue;
dfs_getans(v),sum[u]+=sum[v];
}
} int main(){
memset(head,-1,sizeof head);
n=read(),m=read();
for(register int i=2;i<=n;i++){
int v=read(); long long w=read();
add(i,v,w),add(v,i,w);
}
maxdep=(int)log(n)/log(2),dfs(1);
for(register int i=1;i<=n;i++) size2[i]=size[i]; dfs_getsum(1);
dfs_getans(1); for(register int i=1;i<=n;i++) printf("%d\n",size2[i]-sum[i]);
return 0;
}

[Usaco2012 Dec]Running Away From the Barn的更多相关文章

  1. BZOJ 3011: [Usaco2012 Dec]Running Away From the Barn( dfs序 + 主席树 )

    子树操作, dfs序即可.然后计算<=L就直接在可持久化线段树上查询 -------------------------------------------------------------- ...

  2. BZOJ_3011_[Usaco2012 Dec]Running Away From the Barn _可并堆

    BZOJ_3011_[Usaco2012 Dec]Running Away From the Barn _可并堆 Description 给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于l的 ...

  3. 【BZOJ3011】[Usaco2012 Dec]Running Away From the Barn 可并堆

    [BZOJ3011][Usaco2012 Dec]Running Away From the Barn Description It's milking time at Farmer John's f ...

  4. [BZOJ3011][Usaco2012 Dec]Running Away From the Barn

    题意 给出一棵以1为根节点树,求每个节点的子树中到该节点距离<=l的节点的个数 题解 方法1:倍增+差分数组 首先可以很容易的转化问题,考虑每个节点对哪些节点有贡献 即每次对于一个节点,找到其第 ...

  5. bzoj3011 [Usaco2012 Dec]Running Away From the Barn 左偏树

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3011 题解 复习一下左偏树板子. 看完题目就知道是左偏树了. 结果这个板子还调了好久. 大概已 ...

  6. BZOJ_3012_[Usaco2012 Dec]First!_trie树+拓扑排序

    BZOJ_3012_[Usaco2012 Dec]First!_trie树+拓扑排序 题意: 给定n个总长不超过m的互不相同的字符串,现在你可以任意指定字符之间的大小关系.问有多少个串可能成为字典序最 ...

  7. 【BZOJ3012】[Usaco2012 Dec]First! Trie树+拓补排序

    [BZOJ3012][Usaco2012 Dec]First! Description Bessie has been playing with strings again. She found th ...

  8. [USACO 12DEC]Running Away From the Barn

    Description It's milking time at Farmer John's farm, but the cows have all run away! Farmer John nee ...

  9. USACO Running Away From the Barn /// 可并堆 左偏树维护大顶堆

    题目大意: 给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于等于m的点有多少个 左偏树 https://blog.csdn.net/pengwill97/article/details/82 ...

随机推荐

  1. [日常摸鱼]bzoj2823 [AHOI2012]信号塔

    题意:$n$个点,求最小圆覆盖,$n \leq 5e5$ 这题数据是随机的hhh 我们可以先求出凸包然后对凸包上的点求最小圆覆盖-(不过直接求应该也行?) 反正随便写好像都能过- #include&l ...

  2. [日常摸鱼]luogu3398仓鼠找sugar-树链剖分

    https://www.luogu.org/problemnew/show/P3398 题意:一颗$n$个点的树,$q$次询问两条链$(a,b),(c,d)$是否有交 树剖裸题orz 一开始的想法是求 ...

  3. Shell-匹配行及date日期转换

    #将指定字符串转化为从1970年1月1日到现在的秒数. date -d '20170506' "+%s" #将1970年1月1日到现在累计的秒数转化为日期 date -d @149 ...

  4. MySQL忘记密码了怎么解决

    前言:在不考虑到原来用户对关联数据库的授权问题的情况下,有以下三种思路解决 #1.登录状态下修改 说明:在登录状态的话,直接使用命令修改密码就行了 mysql> use mysql; mysql ...

  5. python初学者-从键盘获取信息

    name = input(">>> 姓名:") QQ = input(">>>QQ: ") phone_num = inpu ...

  6. 【老孟Flutter】2020年总结

    2020年是我经历的最不平凡的一年,这一年有遗憾.有收获,有感概,也有庆幸,庆幸自己还活着. 用一句话总结自己的2020,忙并收获着,累并快乐着. <Flutter 实战入门> <F ...

  7. JS实现JSON数组合并和去重

    var a=[{"id":"1001","name":"张三","age":"18&quo ...

  8. mysql存储过程定义者

    1. 执行update mysql.proc set DEFINER='root@%' WHERE NAME='p_update_rim_batch_log' AND db='otherdataonl ...

  9. [LeetCode]实现数学计算

    乘方 思路是:pow(x,n) = pow(x,n/2)*pow(x,n-n/2) 递归实现 public double myPow(double x, int n) { if (n==0) retu ...

  10. 嵌入式LInux-让开发板访问外网-ping bad address baidu.com

    我的嵌入式设备已经接入网络.能够ping局域网ip.可是为了实现能够ping通外网.比如 ping baidu.com 还是不行的. 当运行ping baidu.com这个命令时,提示 ping ba ...