题意:给一棵树,每次给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; }