对节点X到Y的最短路上所有点权都加一个数W, 查询某个点的权值
解 :
这个操作等价于
a. 对X到根节点路径上所有点权加W
b. 对Y到根节点路径上所有点权加W
c. 对LCA(x, y)到根节点路径上所有点权值减W
d. 对LCA(x,y)的父节点 parent(LCA(x, y))到根节点路径上所有权值减W
于是要进行四次这样从一个点到根节点的区间修改
将问题进一步简化, 进行一个点X到根节点的区间修改, 查询其他一点Y时
只有X在Y的子树内, X对Y的值才有贡献且贡献值为W
于是只需要更新四个点, 查询一个点的子树内所有点权的和即可
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int MAXN = 1e5+10; vector<int> edge[MAXN]; int s[2*MAXN]; int seq[2*MAXN]; int seq1[2*MAXN]; int depth[2*MAXN]; int first[MAXN]; int dp[2*MAXN][25]; int st[MAXN]; int ed[MAXN]; int parent[MAXN]; int cnt, num; int Lowbit(int x) { return x & (-x); } void Add(int x, int val, int n) { if(x <= 0) return; for(int i = x; i <= n; i += Lowbit(i)) { s[i] += val; } } int Sum(int x) { int res = 0; for(int i = x; i > 0; i -= Lowbit(i)) { res += s[i]; } return res; } void Dfs(int u, int fa, int dep) { parent[u] = fa; seq[++cnt] = u; seq1[++num] = u; first[u] = num; depth[num] = dep; st[u] = cnt; int len = edge[u].size(); for(int i = 0; i < len; i++) { int v = edge[u][i]; if(v != fa) { Dfs(v, u, dep+1); seq1[++num] = u; depth[num] = dep; } } seq[++cnt] = u; ed[u] = cnt; } void RMQ_Init(int n) { for(int i = 1; i <= n; i++) { dp[i][0] = i; } for(int j = 1; (1 << j) <= n; j++) { for(int i = 1; i + (1 << j) - 1 <= n; i++) { int a = dp[i][j-1], b = dp[i + (1 << (j-1))][j-1]; dp[i][j] = depth[a] < depth[b] ? a : b; } } } int RMQ_Query(int l, int r) { int k = 0; while((1 << (k + 1)) <= r - l + 1) k++; int a = dp[l][k], b = dp[r-(1<<k)+1][k]; return depth[a] < depth[b] ? a : b; } int LCA(int u, int v) { int a = first[u], b = first[v]; if(a > b) a ^= b, b ^= a, a ^= b; int res = RMQ_Query(a, b); return seq1[res]; } void Init(int n) { for(int i = 0; i <= n; i++) { edge[i].clear(); } memset(s, 0, sizeof(s)); } int main() { int n, op; int u, v, w; int cmd; while(scanf("%d %d", &n, &op) != EOF) { Init(n); for(int i = 0; i < n-1; i++) { scanf("%d %d", &u, &v); edge[u].push_back(v); edge[v].push_back(u); } cnt = 0, num = 0; Dfs(1, -1, 0); RMQ_Init(num); while(op--) { scanf("%d", &cmd); if(cmd == 0) { scanf("%d %d %d", &u, &v, &w); int lca = LCA(u, v); Add(st[u], w, cnt); Add(st[v], w, cnt); Add(lca, -w, cnt); Add(parent[lca], -w, cnt); } else if(cmd == 1) { scanf("%d", &u); printf("%d\n", Sum(ed[u]) - Sum(st[u] - 1)); } } } return 0; }