zoukankan      html  css  js  c++  java
  • UVALive 5061 Lightning Energy Report --LCA

    题意:给一棵树,每次给u到v的路径上所有点加上一个值,最后输出每个点的权值(初始为0)

    解法:每次在u,v间加k时,只要让u,v点的权值加上k,u,v的LCA处减去k(因为LCA的子树中加了两个k),再在LCA的父亲(如果有的话)减k,免除对上面的影响。最后dfs一遍,ans[u] += ans[v] (v是u的所有儿子)即可。

    这里LCA用RMQ求的。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    using namespace std;
    #define N 100107
    
    int fa[N],ans[N];
    vector<int> G[N];
    int ati[N],f[N],bn,b[N],dp[N][32],ind;
    
    void dfs(int u,int fa) {
        for(int i=0;i<G[u].size();i++) {
            int v = G[u][i];
            if(v == fa) continue;
            dfs(v,u);
            ans[u] += ans[v];
        }
    }
    
    void init()
    {
        memset(ati,0,sizeof(ati));
        memset(f,0,sizeof(f));
        memset(b,0,sizeof(b));
        memset(dp,0,sizeof(dp));
        bn = ind = 0;
    }
    
    void dfs_2(int u,int father)
    {
        int tmp = ++ind;
        f[tmp] = u;
        b[++bn] = tmp;
        ati[u] = bn;
        for(int i=0;i<G[u].size();i++)
        {
            int v = G[u][i];
            if(v == father) continue;
            fa[v] = u;
            dfs_2(v,u);
            b[++bn]=tmp;
        }
    }
    
    void RMQ_init(int n)
    {
        for (int i=1; i<=n; i++)  dp[i][0]=b[i];
        int m=floor(log((double)n*1.0)/log((double)2.0));
        for (int j=1; j<=m; j++)
          for (int i=1; i<=n-(1<<j)+1; i++)
              dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
    }
    
    int RMQ(int l,int r)
    {
        int k=floor(log((double)r-l+1)/log(2.0));
        return min(dp[l][k],dp[r-(1<<k)+1][k]);
    }
    
    int LCA(int a,int b)
    {
        if (ati[a] > ati[b]) swap(a,b);
        return f[RMQ(ati[a],ati[b])];
    }
    
    int main()
    {
        int t,cs = 1,i,n,m,u,v,k;
        scanf("%d",&t);
        while(t--)
        {
            init();
            memset(G,0,sizeof(G));
            memset(ans,0,sizeof(ans));
            scanf("%d",&n);
            for(i=0;i<n-1;i++) {
                scanf("%d%d",&u,&v);
                G[u].push_back(v);
                G[v].push_back(u);
            }
            dfs_2(0,-1);
            RMQ_init(bn);
            scanf("%d",&m);
            while(m--) {
                scanf("%d%d%d",&u,&v,&k);
                int lca = LCA(u,v);
                ans[u] += k, ans[v] += k;
                ans[lca] -= k;
                if(lca != 0) ans[fa[lca]] -= k;
            }
            dfs(0,-1);
            printf("Case #%d:
    ",cs++);
            for(i=0;i<n;i++) printf("%d
    ",ans[i]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    golang 数据结构 优先队列(堆)
    leetcode刷题笔记5210题 球会落何处
    leetcode刷题笔记5638题 吃苹果的最大数目
    leetcode刷题笔记5637题 判断字符串的两半是否相似
    剑指 Offer 28. 对称的二叉树
    剑指 Offer 27. 二叉树的镜像
    剑指 Offer 26. 树的子结构
    剑指 Offer 25. 合并两个排序的链表
    剑指 Offer 24. 反转链表
    剑指 Offer 22. 链表中倒数第k个节点
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4231392.html
Copyright © 2011-2022 走看看