zoukankan      html  css  js  c++  java
  • [ JLOI 2012 ] 树

    (\)

    (Description)


    一棵以(1)号节点为根的(N)个节点的树,每个节点有正整数点权(A_i),问有多少条路径的节点点权之和达到(S)

    此处定义的路径中,节点的深度必须是升序的,不能出现由两个点的(Lca)连接的两段路径,路径起点是任意的。

    • (Nin [1,10^5])(A_i,Sin [0,10^3])

    (\)

    (Solution)


    • 树上前缀和的做法显然,记录每个点的树上前缀和,倍增处理(2^k)的祖先。枚举每一个点作为路径的终点,二分起点祖先层数,二进制拆分跳到那里然后前缀和相减验证,总复杂度( ext O(Nlog^2N))

    • 考虑将两个部分合在一起。二分祖先层数是因为不知道这一部分的链上点权和,考虑树上倍增。预处理(f[i][k])表示节点(i)(2^k)层祖先是谁,处理(g[i][k])表示从节点(i)向上长度为(2^k)的链上点权和(()不包括(i),即从(i)的父亲到(i)(2^k)层祖先的链上所有点权和())

    • 在每一个点尝试向上跳,维护当前路径上权值(now)和当前节点位置(x),若存在(f[x][k])(now+g[x][k]le S)就往上跳,判断最后(now)是否与(S)相等即可,总复杂度( ext O(NlogN))

    (\)

    (Code)


    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 100010
    #define R register
    #define gc getchar
    using namespace std;
     
    inline int rd(){
      int x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
     
    int n,m,t,tot,hd[N],val[N];
    int ans,d[N],f[N][20],g[N][20];
    struct edge{int to,nxt;}e[N<<1];
     
    inline void add(int u,int v){
      e[++tot].to=v; e[tot].nxt=hd[u]; hd[u]=tot;
    }
     
    queue<int> q;
    inline void bfs(){
      q.push(1); d[1]=1;
      while(!q.empty()){
        int u=q.front(); q.pop();
        for(R int i=hd[u],v;i;i=e[i].nxt)
          if(!d[v=e[i].to]){
            d[v]=d[u]+1;
            f[v][0]=u; g[v][0]=val[u];
            for(R int i=1;i<=t;++i){
              f[v][i]=f[f[v][i-1]][i-1];
              g[v][i]=g[v][i-1]+g[f[v][i-1]][i-1];
            }
            q.push(v);
          }
      }
    }
     
    inline bool valid(int x){
      int now=val[x];
      for(R int i=t;~i;--i)
        if(f[x][i]&&now+g[x][i]<=m) now+=g[x][i],x=f[x][i];
      return now==m;
    }
     
    int main(){
      t=log2(n=rd()); m=rd();
      for(R int i=1;i<=n;++i) val[i]=rd();
      for(R int i=1,u,v;i<n;++i){
        u=rd(); v=rd();
        add(u,v); add(v,u);
      }
      bfs();
      for(R int i=1;i<=n;++i) ans+=valid(i);
      printf("%d
    ",ans);
      return 0;
    }
    
  • 相关阅读:
    【hdu6035】 Colorful Tree dfs序
    【GDOI2018模拟8】 数学竞赛 三角函数性质+记忆化搜索
    【BZOJ4184】shallot 线性基
    失分统计#1
    【learning】微信跳一跳辅助c++详解 轻松上万 【下】
    【2018北京集训十二】 coin 矩阵快速幂
    【learning】微信跳一跳辅助c++详解 轻松上万 【上】
    【2018北京集训6】Lcm DFT&FWT
    【BZOJ3143】【HNOI2013】游走 高斯消元
    【bzoj1855】 [Scoi2010]股票交易 单调队列优化DP
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9672628.html
Copyright © 2011-2022 走看看