HDU 3966 Aragorn's Story(树链剖分)题解
题意:给一棵树,要求你对一个路径上的值进行加减,查询某个点的值
思路:重链剖分。
由于分了轻重儿子,我每次到重儿子的top只要O(1),经过的轻儿子最多logn条,那么我每次往上跳最多跳logn次。
所以总的路径可以分为:dfn[top[u]]到dfn[u]组成的完整路径,每次更新完走向fa[top[u]]防止重复操作。
参考:某大哥博客
代码:
#include<cmath> #include<set> #include<map> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include <iostream> #include<algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 50000 + 5; const int M = 50 + 5; const ull seed = 131; const int INF = 0x3f3f3f3f; const int MOD = 1000000007; int fa[maxn]; //父节点 int top[maxn]; //i所在重链的初始节点 int sz[maxn]; //i为根子树节点数 int son[maxn]; //重儿子 int deep[maxn]; //深度 int dfn[maxn], tol; //i的dfs序编号 int fd[maxn]; //dfs序编号是i的节点 int aa[maxn]; int n, m; struct Edge{ int v, next; }edge[maxn << 1]; int head[maxn], tot; void init(){ memset(head, -1, sizeof(head)); tot = tol = 0; memset(son, -1, sizeof(son)); } void addEdge(int u, int v){ edge[tot].v = v; edge[tot].next = head[u]; head[u] = tot++; } void dfs1(int u, int pre, int d){ deep[u] = d; fa[u] = pre; sz[u] = 1; for(int i = head[u]; i != -1; i = edge[i].next){ int v = edge[i].v; if(v == pre) continue; dfs1(v, u, d + 1); sz[u] += sz[v]; if(son[u] == -1 || sz[v] > sz[son[u]]) son[u] = v; } } void dfs2(int u, int tp){ //得到top top[u] = tp; dfn[u] = ++tol; fd[tol] = u; if(son[u] == -1) return; dfs2(son[u], tp); for(int i = head[u]; i != -1; i = edge[i].next){ int v = edge[i].v; if(v != son[u] && v != fa[u]){ dfs2(v, v); } } } int sum[maxn << 2], lazy[maxn << 2]; void build(int l, int r, int rt){ if(l == r){ sum[rt] = aa[fd[l]]; lazy[rt] = 0; return; } lazy[rt] = 0; int m = (l + r) >> 1; build(l, m, rt << 1); build(m + 1, r, rt << 1 | 1); sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void pushdown(int rt, int l, int r){ int m = (l + r) >> 1; if(lazy[rt]){ lazy[rt << 1] += lazy[rt]; lazy[rt << 1 | 1] += lazy[rt]; sum[rt << 1] += lazy[rt] * (m - l + 1); sum[rt << 1 | 1] += lazy[rt] * (r - m); lazy[rt] = 0; } } void update(int l, int r, int L, int R, int v, int rt){ if(L <= l && R >= r){ lazy[rt] += v; sum[rt] += v * (r - l + 1); return; } pushdown(rt, l, r); int m = (l + r) >> 1; if(L <= m) update(l, m, L, R, v, rt << 1); if(R > m) update(m + 1, r, L, R, v, rt << 1 | 1); sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } int query(int pos, int l, int r, int rt){ if(l == r){ return sum[rt]; } pushdown(rt, l, r); int m = (l + r) >> 1; if(pos <= m) return query(pos, l, m, rt << 1); else return query(pos, m + 1, r, rt << 1 | 1); } void add(int u, int v, int val){ while(top[u] != top[v]){ if(deep[top[u]] < deep[top[v]]) swap(u, v); update(1, n, dfn[top[u]], dfn[u], val, 1); u = fa[top[u]]; } if(deep[u] > deep[v]) swap(u, v); update(1, n, dfn[u], dfn[v], val, 1); } int main(){ int Q; while(~scanf("%d%d%d", &n, &m, &Q)){ init(); for(int i = 1; i <= n; i++){ scanf("%d", &aa[i]); } for(int i = 0; i < m; i++){ int u, v; scanf("%d%d", &u, &v); addEdge(u, v); addEdge(v, u); } dfs1(1, -1, 0); dfs2(1, 1); build(1, n, 1); while(Q--){ char o[2]; int a, b, c; scanf("%s", o); if(o[0] == 'I'){ scanf("%d%d%d", &a, &b, &c); add(a, b, c); } else if(o[0] == 'D'){ scanf("%d%d%d", &a, &b, &c); add(a, b, -c); } else{ scanf("%d", &a); printf("%d\n", query(dfn[a], 1, n, 1)); } } } return 0; }