Fork me on GitHub

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:\n",cs++);
        for(i=0;i<n;i++) printf("%d\n",ans[i]);
    }
    return 0;
}
View Code

 

posted @ 2015-01-18 18:24  whatbeg  阅读(253)  评论(0编辑  收藏  举报