• 树上跳跃


    题目描述
    懒惰的温温今天上班也在偷懒。盯着窗外发呆的温温发现,透过窗户正巧能看到一棵n个节点的树。一棵n个节点的树包含n-1条边,且n个节点是联通的。树上两点之间的距离即两点之间的最短路径包含的边数。
    温温瞧见树上有一只灵活的小松鼠正在节点间跳来跳去。观察了很长一段时间之后,温温发现:松鼠每次跳跃,从当前节点可以跳到任何与当前节点距离不超过k的节点。
    突发奇想的温温想要知道,如果定义f(u, v)为从松鼠从u点到v点所需的最少跳跃次数,那么,对于树上的所有点对(u, v),f(u, v)的总和是多少。
    注意:(u, v)和(v, u)视作同一个点对,只计算一次答案。

    输入
    第一行两个整数n和k。
    接下来n-1行每行两个整数ai, bi,表示节点ai和bi之间存在一条边。

    1 ≤ k ≤ 5
    2 ≤ n ≤ 5000 for 40%
    2 ≤ n ≤ 200000 for 100%

    输出

    输出一个整数,表示所求的f(u, v)总和。

    样例输入 Copy
    【样例1】

    6 2
    1 2
    1 3
    2 4
    2 5
    4 6

    【样例2】

    13 3
    1 2
    3 2
    4 2
    5 2
    3 6
    10 6
    6 7
    6 13
    5 8
    5 9
    9 11
    11 12

    样例输出 Copy
    【样例1】

    20

    【样例2】

    114

    #include <bits/stdc++.h>
    using namespace std ;
    typedef long long ll ;
    const int N = 2e5 + 10 ;
    int e[N << 1] , ne[N << 1] , h[N << 1]  , idx , flow[N] , in[N] , dp[N][6] , size[N] , k , b[6] , n ;
    void add(int a, int b)
    {
        e[idx] = b , ne[idx] = h[a] , h[a] = idx ++ ;
    }
    void dfs1(int u , int fa)
    {
        memset(b , 0 , sizeof b) ;
        if(fa)
         {
           b[0] = dp[fa][0] - dp[u][k - 1] - size[u] ;
           for(int i = 1; i < k ;i ++) b[i] = dp[fa][i] - dp[u][i - 1] ;
         }
        dp[u][0] += b[k - 1] + n - size[u] ;
        for(int i = 1 ; i < k ;i ++) dp[u][i] += b[i - 1] ;
        for(int i = h[u] ; ~i ; i = ne[i])
        {
            int v = e[i] ;
            if(v == fa) continue ;
            dfs1(v , u) ;
        }
    }
    void dfs(int u , int fa)
    {
        size[u] = 1 ;
        for(int i = h[u] ; ~i ; i = ne[i])
        {
            int v = e[i] ;
            if(v == fa) continue ;
            dfs(v , u) ;
            size[u] += size[v] ;
            dp[u][0] += dp[v][k - 1] + size[v] ;
            for(int i = 1; i < k ;i ++) dp[u][i] += dp[v][i - 1] ;
        }
        return ;
    }
    void work()
    {
        cin >> n >> k ;
        memset(flow , 0 , sizeof flow) ;
        idx = 0 ;
        memset(h , -1 , sizeof h) ;
        for(int i = 1 , a , b , c ; i < n ;i ++)
            cin >> a >> b  ,
            add(a , b) , add(b , a);
        dfs(1, 0) ;
        dfs1(1 , 0) ;
        ll res = 0 ;
        for(int i = 1; i <= n ;i ++) res += 1ll * dp[i][0] ;
        cout << res / 2 << endl ;
        return ;
    }
    int main()
    {
        work() ;
        return 0 ;
    }
    
    
  • 相关阅读:
    如何突破单库性能瓶颈?
    高性能数据库表该如何设计?
    高性能索引该如何设计?(下)
    高性能索引该如何设计?(上)
    MySQL体系结构与存储引擎
    动态ViewPager导航页面
    ViewPager图片轮转带点的
    手动图片横向轮播
    安卓布局中下拉列表框的实现
    安卓中adapter的应用
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/12870847.html
Copyright © 2020-2023  润新知