Aragorn's Story 【HDU - 3966】【樹鏈剖分】
阿新 • • 發佈:2018-11-30
題目連結
樹鏈剖分的學習筆記(更新中)
這道題所給的Hint好有迷惑性,它跟我們說注意士兵的數量可能為負數,我的第一反應是,士兵的數量是不是不能為負數,那麼我們是不是要做出些什麼調整,然而,語文不好的我看了Discuss才知道說的是:士兵的數量可以為負數。這樣也好,題目就變成了一道簡單的樹鏈剖分問題了,我們只需要記錄每個節點的深度,以及它的最頂節點,然後邊更新就是了。
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxN = 50005; int N, M, Q, cnt, head[maxN], root[maxN], depth[maxN], size[maxN], W_Son[maxN], top[maxN], w[maxN], new_W[maxN], id[maxN], num; ll tree[maxN<<2], lazy[maxN<<2]; struct Eddge { int nex, to; Eddge(int a=-1, int b=0):nex(a), to(b) {} }edge[maxN<<1]; void addEddge(int u, int v) { edge[cnt] = Eddge(head[u], v); head[u] = cnt++; } void dfs1(int u, int fa, int deep) { root[u] = fa; depth[u] = deep; size[u] = 1; int maxxSon = -1; for(int i=head[u]; i!=-1; i=edge[i].nex) { int v = edge[i].to; if(v == fa) continue; dfs1(v, u, deep+1); size[u] += size[v]; if(size[v] > maxxSon) { maxxSon = size[v]; W_Son[u] = v; } } } void dfs2(int x, int topf) { top[x] = topf; id[x] = ++num; new_W[num] = w[x]; if(!W_Son[x]) return; dfs2(W_Son[x], topf); for(int i=head[x]; i!=-1; i=edge[i].nex) { int y = edge[i].to; if(y == root[x] || y == W_Son[x]) continue; dfs2(y, y); } } void pushup(int rt) { tree[rt] = tree[rt<<1] + tree[rt<<1|1]; } void buildTree(int rt, int l, int r) { lazy[rt] = 0; if(l == r) { tree[rt] = new_W[l]; return; } int mid = (l + r)>>1; buildTree(rt<<1, l, mid); buildTree(rt<<1|1, mid+1, r); pushup(rt); } void pushdown(int rt, int l, int r) { if(lazy[rt]) { int mid = (l + r)>>1; lazy[rt<<1] += lazy[rt]; lazy[rt<<1|1] += lazy[rt]; tree[rt<<1] += lazy[rt]*(mid - l + 1); tree[rt<<1|1] += lazy[rt]*(r - mid); lazy[rt] = 0; } } void update(int rt, int l, int r, int ql, int qr, int val) { if(ql<=l && qr>=r) { lazy[rt] += val; tree[rt] += val*(r - l + 1); return; } pushdown(rt, l, r); int mid = (l + r)>>1; if(ql>mid) update(rt<<1|1, mid+1, r, ql, qr, val); else if(qr<=mid) update(rt<<1, l, mid, ql, qr, val); else { update(rt<<1|1, mid+1, r, ql, qr, val); update(rt<<1, l, mid, ql, qr, val); } pushup(rt); } ll query(int rt, int l, int r, int ql, int qr) { if(ql<=l && qr>=r) return tree[rt]; pushdown(rt, l, r); int mid = (l + r)>>1; if(ql>mid) return query(rt<<1|1, mid+1, r, ql, qr); else if(qr<=mid) return query(rt<<1, l, mid, ql, qr); else { ll ans = query(rt<<1|1, mid+1, r, ql, qr); ans += query(rt<<1, l, mid, ql, qr); return ans; } } void update_Range(int x, int y, int val) { while(top[x] != top[y]) { if(depth[top[x]] < depth[top[y]]) swap(x, y); update(1, 1, N, id[top[x]], id[x], val); x = root[top[x]]; } if(depth[x] > depth[y]) swap(x, y); update(1, 1, N, id[x], id[y], val); } ll query_Point(int x) { return query(1, 1, N, id[x], id[x]); } void init() { cnt = num = 0; memset(head, -1, sizeof(head)); memset(W_Son, 0, sizeof(W_Son)); } int main() { while(scanf("%d%d%d", &N, &M, &Q)!=EOF) { init(); for(int i=1; i<=N; i++) scanf("%d", &w[i]); int e1, e2; for(int i=1; i<=M; i++) { scanf("%d%d", &e1, &e2); addEddge(e1, e2); addEddge(e2, e1); } dfs1(1, 1, 0); dfs2(1, 1); buildTree(1, 1, N); while(Q--) { char s[3]; scanf("%s", s); if(s[0] == 'I') { int L, R, val; scanf("%d%d%d", &L, &R, &val); update_Range(L, R, val); } else if(s[0] == 'D') { int L, R, val; scanf("%d%d%d", &L, &R, &val); update_Range(L, R, -val); } else { int X; scanf("%d", &X); printf("%lld\n", query_Point(X)); } } } return 0; }