UVALive 5061

The city of Thunder has many houses and they are powered by lightning. Two houses may be interconnected by a wire. The wires connect the houses such that there is exactly one path from one house to any other house in the city. Each house has a large battery that can store infinite electrical energy.

Everyday, several lightnings strike several houses. These lightnings are very unusual, when it strikes, it strikes two houses simultaneously: one house (A) with a red lightning and the other house (B) with a blue lightning. After the strikes, every house along the path from A to B (inclusive) will receive a certain amount of electrical energy which is then added to the house's battery.

The mayor of Thunder city wants a report on the stored electrical energy for every house at the end of the month and the owner of each house has to pay taxes for that. To prevent the owners report invalid energy stored in their house battery (because they want less tax to pay), you are asked to produce a correct report based on the observed lightnings of the current month. At the beginning of the month, the energy reading on the battery of each house is 0.

Input 

The first line of input contains an integer T (T$ \le$10), the number of cases. Each case begins with an integerN (2$ \le$N$ \le$50, 000), the number of houses in the Thunder city. The next N - 1 lines contain the wire connections where each line will consist of two integers X and Y which means house X is connected with houseY. The house number is from 0 to N - 1. The next line will contain a number Q (1$ \le$Q$ \le$50, 000) which denotes the number of observed lightning strikes. The next Q lines describe the unusual lightnings happened during the month. Each line will consist of three integers ABC which tells that a red lightning strikes house Aand a blue lightning strikes house B and the power transferred is C (at most 100) based on the reading of a special lightning instrument.

Output 

For each case, output ``Case #X:" (without quote) where X is the case number and N lines where each line is the electrical energy reading on the battery of each house from house 0 to house N - 1 at the end of the month.

Sample Input 

1 
9 
0 1
1 2
2 3
2 4
2 7
7 8
7 6
6 5
5 
1 4 10 
3 5 3 
0 8 5 
1 6 10 
4 4 100

Sample Output 

Case #1: 
5 
25 
28 
3 
110 
3 
13 
18 
5


题意很简单,给你一棵树。先给出很多操作(x,y)即把x到y路径上的点权都加上z。最后输出每个点最终的点权。

方法是求出x,y的最近公共祖先p=lca(x,y);(本题可以用tarjan,也可以用rmq)

对于每一次操作,执行以下几步;

w[x]+=z;

w[y]+=z;

w[p]-=z;

w[fa[p]]-=z;

其中fa[x]为x的父亲,fa[root]随便设一个值,比如fa[root]=n+1;

之后对图做一次dfs在回溯的时候累加上权值就可以了。具体看代码,最好用手画个例子推一下。


#include<cstdio>
#include<cstring>
#include<vector>
#include<cstdlib>
#define maxn 50009
using namespace std;
vector<int>G[maxn];
int a[maxn][20];
int tin[maxn],tout[maxn],t,ans[maxn],w[maxn],pa[maxn];
int n,m;
void dfs(int x,int px)
{
    tin[x]=t++;
    a[x][0]=px;
    if(x)pa[x]=px;
    else pa[x]=n+1;
    for(int i=1;1<<i<n/2;i++)
        a[x][i]=a[a[x][i-1]][i-1];
    for(int i=0;i<G[x].size();i++)
    {
        int v=G[x][i];
        if(v!=px)
            dfs(v,x);
    }
    tout[x]=t++;
}
bool act(int x,int y)
{
    return tin[x]<=tin[y]&&tout[y]<=tout[x];
}
int log2(int x)
{
    int i=0;
    while(1<<i<=x)i++;
    return i-1;
}
int lca(int x,int y)
{
    if(act(x,y))return x;
    if(act(y,x))return y;
    for(int i=log2(n/2);i>=0;i--)
        if(!act(a[x][i],y))
        x=a[x][i];
    return a[x][0];
}
void init()
{
    memset(a,0,sizeof(a));
    t=0;dfs(0,0);
}
void dp(int cur,int fa)
{
    for(int i=0;i<G[cur].size();i++)
    {
        int v=G[cur][i];
        if(v!=fa){
            dp(v,cur);
            ans[cur]+=ans[v];  //先处理子树,再用子树的结果去累加
        }
    }
    ans[cur]+=w[cur]; //最后加上自己的权值
}
int main()
{
    int tt;
    scanf("%d",&tt);
    int cot=0;
    while(tt--)
    {
        scanf("%d",&n);cot++;
        for(int i=0;i<=n;i++)G[i].clear();
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        init();
        scanf("%d",&m);
        memset(w,0,sizeof(w));
        memset(ans,0,sizeof(ans));
        for(int i=0;i<m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            w[x]+=z;
            w[y]+=z;
            w[lca(x,y)]-=z;
            w[pa[lca(x,y)]]-=z;
        }
        dp(0,0);
        printf("Case #%d:\n",cot);
        for(int i=0;i<n;i++)
            printf("%d\n",ans[i]);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值