[hdu3966 Aragorn's Story]树链剖分
题意:要求在一棵N(<=50000)个带权节点的树上支持3种操作
(1)I u v w,u到v的路径上每个节点权值增加w
(2)D u v w,u到v的路径上每个节点权值减少w
(3)Q u,求u点的权值
思路:
将树剖分成若干条链,然后用区间数据结构来维护,这就是树链剖分。树链剖分后,这个题可以转化为一个“区间修改,单点查询”的问题,树状数组或线段树即可。
树状数组(1100ms):
#pragma comment(linker, "/STACK:10240000,10240000") #include <iostream> #include <cstdio> #include <ctime> #include <cstring> using namespace std; #define X first #define Y second #define pb(x) push_back(x) #define mp(x, y) make_pair(x, y) #define all(a) (a).begin(), (a).end() #define mset(a, x) memset(a, x, sizeof(a)) #define mcpy(a, b) memcpy(a, b, sizeof(b)) #define cas() int T, cas = 0; cin >> T; while (T --) template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;} template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;} typedef long long ll; typedef pair<int, int> pii; #ifndef ONLINE_JUDGE #include "local.h" #endif const int N = 5e4 + 7; const int M = N; namespace Edge { int last[N], to[M << 1], next[M << 1], cntE; void init() { cntE = 0; memset(last, -1, sizeof(last)); } void addEdge(int u, int v) { to[cntE] = v; next[cntE] = last[u]; last[u] = cntE ++; } } namespace TreeChain { int dep[N], top[N], w[N], son[N], siz[N], fa[N]; int id[N], rnk[N], cntID; void init() { cntID = 0; memset(son, -1, sizeof(son)); } void dfs1(int u, int f, int d) { dep[u] = d; fa[u] = f; siz[u] = 1; for (int i = Edge::last[u]; ~i; i = Edge::next[i]) { int v = Edge::to[i]; if (v != f) { dfs1(v, u, d + 1); siz[u] += siz[v]; if (son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v; } } } void dfs2(int u, int t) { top[u] = t; id[u] = ++ cntID; rnk[id[u]] = u; if (son[u] == -1) return; dfs2(son[u], t); for (int i = Edge::last[u]; ~i; i = Edge::next[i]) { int v = Edge::to[i]; if (v != son[u] && v != fa[u]) dfs2(v, v); } } } int a[N]; namespace TreeArray { int c[N], n; void init(int n) { memset(c, 0, sizeof(c)); TreeArray::n = n; } int lowbit(int x) { return x & -x; } void add(int p, int x) { while (p <= n) { c[p] += x; p += lowbit(p); } } void add(int l, int r, int x) { add(l, x); add(r + 1, -x); } int query(int p) { int ans = 0; while (p) { ans += c[p]; p -= lowbit(p); } return ans; } void change(int u, int v, int w) { using namespace TreeChain; while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u, v); add(id[top[u]], id[u], w); u = fa[top[u]]; } if (dep[u] > dep[v]) swap(u, v); add(id[u], id[v], w); } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int n, m, p, u, v, w; char s[2]; while (cin >> n >> m >> p) { Edge::init(); TreeChain::init(); for (int i = 1; i <= n; i ++) { scanf("%d", a + i); } for (int i = 0; i < m; i ++) { scanf("%d%d", &u, &v); Edge::addEdge(u, v); Edge::addEdge(v, u); } TreeChain::dfs1(1, 0, 0); TreeChain::dfs2(1, 1); TreeArray::init(n); for (int i = 1; i <= n; i ++) { TreeArray::add(i, i, a[TreeChain::rnk[i]]); } for (int i = 0; i < p; i ++) { scanf("%s", s); if (*s == 'Q') { scanf("%d", &u); printf("%d\n", TreeArray::query(TreeChain::id[u])); } else { scanf("%d%d%d", &u, &v, &w); if (*s == 'D') w = -w; TreeArray::change(u, v, w); } } } return 0; }
线段树(1900ms):
#pragma comment(linker, "/STACK:10240000,10240000") #include <iostream> #include <cstdio> #include <ctime> #include <cstring> using namespace std; #define X first #define Y second #define pb(x) push_back(x) #define mp(x, y) make_pair(x, y) #define all(a) (a).begin(), (a).end() #define mset(a, x) memset(a, x, sizeof(a)) #define mcpy(a, b) memcpy(a, b, sizeof(b)) #define cas() int T, cas = 0; cin >> T; while (T --) template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;} template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;} typedef long long ll; typedef pair<int, int> pii; #ifndef ONLINE_JUDGE #include "local.h" #endif const int N = 5e4 + 7; const int M = N; namespace Edge { int last[N], to[M << 1], next[M << 1], cntE; void init() { cntE = 0; memset(last, -1, sizeof(last)); } void addEdge(int u, int v) { to[cntE] = v; next[cntE] = last[u]; last[u] = cntE ++; } } namespace TreeChain { int dep[N], top[N], w[N], son[N], siz[N], fa[N]; int id[N], rnk[N], cntID; void init() { cntID = 0; memset(son, -1, sizeof(son)); } void dfs1(int u, int f, int d) { dep[u] = d; fa[u] = f; siz[u] = 1; for (int i = Edge::last[u]; ~i; i = Edge::next[i]) { int v = Edge::to[i]; if (v != f) { dfs1(v, u, d + 1); siz[u] += siz[v]; if (son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v; } } } void dfs2(int u, int t) { top[u] = t; id[u] = ++ cntID; rnk[id[u]] = u; if (son[u] == -1) return; dfs2(son[u], t); for (int i = Edge::last[u]; ~i; i = Edge::next[i]) { int v = Edge::to[i]; if (v != son[u] && v != fa[u]) dfs2(v, v); } } } int a[N]; namespace SegTree { #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 int sum[N << 2], mark[N << 2]; void up(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void down(int rt, int len) { int rlen = len >> 1, llen = len - rlen; if (mark[rt]) { sum[rt << 1] += llen * mark[rt]; mark[rt << 1] += mark[rt]; sum[rt << 1 | 1] += rlen * mark[rt]; mark[rt << 1 | 1] += mark[rt]; mark[rt] = 0; } } void build(int l, int r, int rt) { mark[rt] = 0; if (l == r) { sum[rt] = a[TreeChain::rnk[l]]; return; } int m = (l + r) >> 1; build(lson); build(rson); up(rt); } void update(int L, int R, int x, int l, int r, int rt) { if (L <= l && r <= R) { sum[rt] += (r - l + 1) * x; mark[rt] += x; return; } int m = (l + r) >> 1; down(rt, r - l + 1); if (L <= m) update(L, R, x, lson); if (R > m) update(L, R, x, rson); up(rt); } int query(int p, int l, int r, int rt) { if (l == r) return sum[rt]; int m = (l + r) >> 1; down(rt, r - l + 1); if (p <= m) return query(p, lson); else return query(p, rson); } void change(int u, int v, int w, int n) { using namespace TreeChain; while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u, v); update(id[top[u]], id[u], w, 1, n, 1); u = fa[top[u]]; } if (dep[u] > dep[v]) swap(u, v); update(id[u], id[v], w, 1, n, 1); } #undef lson #undef rson } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int n, m, p, u, v, w; char s[2]; while (cin >> n >> m >> p) { Edge::init(); TreeChain::init(); for (int i = 1; i <= n; i ++) { scanf("%d", a + i); } for (int i = 0; i < m; i ++) { scanf("%d%d", &u, &v); Edge::addEdge(u, v); Edge::addEdge(v, u); } TreeChain::dfs1(1, 0, 0); TreeChain::dfs2(1, 1); SegTree::build(1, n, 1); for (int i = 0; i < p; i ++) { scanf("%s", s); if (*s == 'Q') { scanf("%d", &u); printf("%d\n", SegTree::query(TreeChain::id[u], 1, n, 1)); } else { scanf("%d%d%d", &u, &v, &w); if (*s == 'D') w = -w; SegTree::change(u, v, w, n); } } } return 0; }