• P3066 [USACO12DEC]逃跑的BarnRunning Away From (树上二分)


    题意

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

    树上二分.
    这个做法还是基于树上差分的,也就是对于每一个点uu,我们要找到它向上跳LL的长度最高能够跳到的祖先.(当然倍增求出这个连dfsdfs都不用更加粗暴.)
    因此我们不仅要记录每一个节点到根节点的距离disdis,还要记录每一个节点到根节点要经过边的边数,也即点的深度depdep.
    然后再用tmptmp数组记录从根节点到uu经过的每一个点,tmp[i]tmp[i]表示从根节点到uu的路径上深度为ii的节点的编号,
    只要用tmp[dep[u]]=u一句话就可以记录了.
    记录了路径上的点,接下来神奇的事情发生了.
    可以发现,路径上的点到根的距离是单调递增的,我们在tmptmp数组里二分可以找到离uu距离不超过LL的最高祖先. 这样对每个点都差分,最后dfsdfs处理一遍就可以了.

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int yuzu=2e5;
    typedef int fuko[yuzu|10];
    typedef ll rize[yuzu|10];
    struct edge{int to; ll c;};
    vector<edge> lj[yuzu|10];
    fuko fa,ans,dep,tmp,cha;
    rize dis;
    
    void dfs(int u,ll len) {
    dep[u]=dep[fa[u]]+1; // 求节点u的深度
    tmp[dep[u]]=u; // 记录从根节点到u深度为dep[u]的点.
    int l=1,r=dep[u],mid;
    for (;l<r;dis[u]-dis[tmp[mid]]<=len?r=mid:l=mid+1) mid=l+r>>1;
    /*在这条路径上二分能跳到的最高祖先*/
    cha[fa[tmp[l]]]--,cha[u]++; // 差分
    for (edge i:lj[u])
      dis[i.to]=dis[u]+i.c,dfs(i.to,len);
    }
    
    int main() {
    int i,n; ll l,x;
    scanf("%d%lld",&n,&l);
    for (i=2;i<=n;++i)
      scanf("%d%lld",&fa[i],&x),
      lj[fa[i]].push_back(edge{i,x});
    dfs(1,l);
    for (i=n;i;--i) cha[fa[i]]+=cha[i];
    /*由于每个点的父节点已知并且肯定比原节点编号小,可以倒过来用一个循环代替dfs*/
    for (i=1;i<=n;++i) printf("%d
    ",cha[i]);
    }
    View Code
  • 相关阅读:
    针对Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1的解决方案
    MAC配置C++运行环境
    Keras 模型相关操作
    微信小程序 WXS
    vue 长列表优化
    webpack4 SplitChunks插件 代码拆分
    node path api
    mysql的模型依赖说明
    MySQL和MyCat replace
    SQL Server中WITH(NOLOCK)提示用在视图上会怎样(转载)
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/10484526.html
Copyright © 2020-2023  润新知