题意:给一棵树,每次给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][],ind; void dfs(int u,int fa) {
for(int i=;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,,sizeof(ati));
memset(f,,sizeof(f));
memset(b,,sizeof(b));
memset(dp,,sizeof(dp));
bn = ind = ;
} void dfs_2(int u,int father)
{
int tmp = ++ind;
f[tmp] = u;
b[++bn] = tmp;
ati[u] = bn;
for(int i=;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=; i<=n; i++) dp[i][]=b[i];
int m=floor(log((double)n*1.0)/log((double)2.0));
for (int j=; j<=m; j++)
for (int i=; i<=n-(<<j)+; i++)
dp[i][j]=min(dp[i][j-],dp[i+(<<(j-))][j-]);
} int RMQ(int l,int r)
{
int k=floor(log((double)r-l+)/log(2.0));
return min(dp[l][k],dp[r-(<<k)+][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 = ,i,n,m,u,v,k;
scanf("%d",&t);
while(t--)
{
init();
memset(G,,sizeof(G));
memset(ans,,sizeof(ans));
scanf("%d",&n);
for(i=;i<n-;i++) {
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs_2(,-);
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 != ) ans[fa[lca]] -= k;
}
dfs(,-);
printf("Case #%d:\n",cs++);
for(i=;i<n;i++) printf("%d\n",ans[i]);
}
return ;
}